@leofcoin/peernet 0.11.24 → 0.11.25

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.
@@ -13,17 +13,15 @@ __webpack_require__(307);
13
13
  var pako = __webpack_require__(9591);
14
14
  var LeofcoinStorage = __webpack_require__(1116);
15
15
  var protons = __webpack_require__(7160);
16
- var bs32 = __webpack_require__(103);
17
- var bs58 = __webpack_require__(158);
18
- var isHex = __webpack_require__(6187);
19
- var varint = __webpack_require__(4676);
20
- var createKeccakHash = __webpack_require__(5811);
16
+ var codecFormatInterface = __webpack_require__(5698);
21
17
  var MultiWallet$1 = __webpack_require__(9755);
22
18
  var bs58check = __webpack_require__(8334);
23
19
  var bip32 = __webpack_require__(7786);
20
+ var createKeccakHash = __webpack_require__(5811);
24
21
  var ecc = __webpack_require__(5892);
25
22
  var Mnemonic = __webpack_require__(4911);
26
23
  var MultiSignature = __webpack_require__(6697);
24
+ var varint = __webpack_require__(4676);
27
25
  var randombytes = __webpack_require__(1798);
28
26
 
29
27
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -49,18 +47,15 @@ function _interopNamespace(e) {
49
47
  var pako__default = /*#__PURE__*/_interopDefaultLegacy(pako);
50
48
  var LeofcoinStorage__default = /*#__PURE__*/_interopDefaultLegacy(LeofcoinStorage);
51
49
  var protons__default = /*#__PURE__*/_interopDefaultLegacy(protons);
52
- var bs32__default = /*#__PURE__*/_interopDefaultLegacy(bs32);
53
- var bs58__default = /*#__PURE__*/_interopDefaultLegacy(bs58);
54
- var isHex__default = /*#__PURE__*/_interopDefaultLegacy(isHex);
55
- var varint__default = /*#__PURE__*/_interopDefaultLegacy(varint);
56
- var createKeccakHash__default = /*#__PURE__*/_interopDefaultLegacy(createKeccakHash);
57
50
  var MultiWallet__default = /*#__PURE__*/_interopDefaultLegacy(MultiWallet$1);
58
51
  var bs58check__default = /*#__PURE__*/_interopDefaultLegacy(bs58check);
59
52
  var bs58check__namespace = /*#__PURE__*/_interopNamespace(bs58check);
60
53
  var bip32__namespace = /*#__PURE__*/_interopNamespace(bip32);
54
+ var createKeccakHash__default = /*#__PURE__*/_interopDefaultLegacy(createKeccakHash);
61
55
  var ecc__default = /*#__PURE__*/_interopDefaultLegacy(ecc);
62
56
  var Mnemonic__default = /*#__PURE__*/_interopDefaultLegacy(Mnemonic);
63
57
  var MultiSignature__default = /*#__PURE__*/_interopDefaultLegacy(MultiSignature);
58
+ var varint__default = /*#__PURE__*/_interopDefaultLegacy(varint);
64
59
  var randombytes__default = /*#__PURE__*/_interopDefaultLegacy(randombytes);
65
60
 
66
61
  /* socket-request-client version 1.6.3 */
@@ -771,1425 +766,891 @@ message PeernetMessage {
771
766
  optional string id = 5;
772
767
  }`;
773
768
 
774
- var codecs = {
775
- // just a hash
776
- 'disco-hash': {
777
- codec: parseInt('30', 16),
778
- hashAlg: 'dbl-keccak-256', // ,
779
- // testnet: 'olivia'
780
- },
781
- 'peernet-peer-response': {
782
- codec: parseInt('707072', 16),
783
- hashAlg: 'keccak-256',
784
- },
785
- 'peernet-peer': {
786
- codec: parseInt('7070', 16),
787
- hashAlg: 'keccak-256',
788
- },
789
- 'peernet-dht': {
790
- codec: parseInt('706468', 16),
791
- hashAlg: 'keccak-256',
792
- },
793
- 'peernet-dht-response': {
794
- codec: parseInt('706472', 16),
795
- hashAlg: 'keccak-256',
796
- },
797
- // data
798
- 'peernet-data': {
799
- codec: parseInt('706461', 16),
800
- hashAlg: 'keccak-256',
801
- },
802
- 'peernet-data-response': {
803
- codec: parseInt('70646172', 16),
804
- hashAlg: 'keccak-256',
805
- },
806
- // message
807
- 'peernet-message': {
808
- codec: parseInt('706d65', 16),
809
- hashAlg: 'keccak-256',
810
- },
811
- // pubsub
812
- 'peernet-ps': {
813
- codec: parseInt('707073', 16),
814
- hashAlg: 'keccak-256',
815
- },
816
- 'peernet-response': {
817
- codec: parseInt('7072', 16),
818
- hashAlg: 'keccak-256',
819
- },
820
- 'peernet-request': {
821
- codec: parseInt('707271', 16),
822
- hashAlg: 'keccak-256',
823
- },
824
- // normal block
825
- 'leofcoin-block': {
826
- codec: parseInt('6c62', 16),
827
- hashAlg: 'dbl-keccak-512', // ,
828
- // testnet: 'olivia'
829
- },
830
- 'leofcoin-tx': {
831
- codec: parseInt('6c74', 16),
832
- hashAlg: 'dbl-keccak-512', // ,
833
- // testnet: 'olivia'
834
- },
835
- // itx
836
- 'leofcoin-itx': {
837
- codec: parseInt('6c69', 16),
838
- hashAlg: 'keccak-512', // ,
839
- // testnet: 'olivia'
840
- },
841
- // peer reputation
842
- 'leofcoin-pr': {
843
- codec: parseInt('6c70', 16),
844
- hashAlg: 'keccak-256', // ,
845
- // testnet: 'olivia'
846
- },
847
- // chat message
848
- 'chat-message': {
849
- codec: parseInt('636d', 16),
850
- hashAlg: 'dbl-keccak-256',
851
- },
852
- };
853
-
854
- class PeernetCodec {
855
- get codecs() {
856
- return {...globalThis.peernet.codecs, ...codecs}
769
+ class PeernetMessage extends codecFormatInterface.FormatInterface {
770
+ get keys() {
771
+ return ['data', 'signature', 'from', 'to', 'id']
857
772
  }
858
- constructor(buffer) {
859
- if (buffer) {
860
- if (buffer instanceof Uint8Array) {
861
- const codec = varint__default["default"].decode(buffer);
862
- const name = this.getCodecName(codec);
863
- if (name) {
864
- this.name = name;
865
- this.encoded = buffer;
866
- this.decode(buffer);
867
- } else {
868
- this.encode(buffer);
869
- }
870
- } else if (buffer instanceof ArrayBuffer) {
871
- const encoded = new Uint8Array(buffer.byteLength);
872
773
 
873
- for (let i = 0; i < buffer.byteLength; i++) {
874
- encoded[i] = buffer[i];
875
- }
876
- this.encoded = encoded;
877
- // this.encoded = new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength)
878
- this.decode(buffer);
879
- return
880
- }
881
- if (typeof buffer === 'string') {
882
- if (this.codecs[buffer]) this.fromName(buffer);
883
- else if (isHex__default["default"](buffer)) this.fromHex(buffer);
884
- else if (bs32__default["default"].isBase32(buffer)) this.fromBs32(buffer);
885
- else if (bs58__default["default"].isBase58(buffer)) this.fromBs58(buffer);
886
- else throw new Error(`unsupported string ${buffer}`)
887
- }
888
- if (!isNaN(buffer)) if (this.codecs[this.getCodecName(buffer)]) this.fromCodec(buffer);
889
- }
774
+ constructor(buffer) {
775
+ const name = 'peernet-message';
776
+ super(buffer, protons__default["default"](proto$a).PeernetMessage, {name});
890
777
  }
891
-
892
- fromEncoded(encoded) {
893
- const codec = varint__default["default"].decode(encoded);
894
- const name = this.getCodecName(codec);
895
- this.name = name;
896
- this.encoded = encoded;
897
- this.decode(encoded);
778
+ }
779
+
780
+ var proto$9 = `
781
+ // PeernetDHTMessage
782
+ message PeernetDHTMessage {
783
+ required string hash = 1;
784
+ optional string store = 2;
785
+ }
786
+ `;
787
+
788
+ /**
789
+ * @example `
790
+ new DHTMessage(hash, store)
791
+ // store = optional if not set, peernet checks every store
792
+ let message = new DHTMessage('hashmvbs124xcfd...', 'transaction')
793
+ message = new DHTMessage('hashmvbs124xcfd...', 'block')
794
+ `
795
+ */
796
+ class DHTMessage extends codecFormatInterface.FormatInterface {
797
+ /**
798
+ *
799
+ */
800
+ get keys() {
801
+ return ['hash', 'store']
898
802
  }
899
803
 
900
- fromHex(hex) {
901
- this.encoded = Buffer.from(hex, 'hex');
902
- this.decode();
804
+ constructor(data) {
805
+ const name = 'peernet-dht';
806
+ super(data, protons__default["default"](proto$9).PeernetDHTMessage, {name});
903
807
  }
904
-
905
- fromBs32(input) {
906
- this.encoded = bs32__default["default"].decode(input);
907
- this.decode();
808
+ }
809
+
810
+ var proto$8 = `
811
+ // PeernetDHTMessageResponse
812
+ message PeernetDHTMessageResponse {
813
+ required string hash = 1;
814
+ required bool has = 2;
815
+ }
816
+ `;
817
+
818
+ class DHTMessageResponse extends codecFormatInterface.FormatInterface {
819
+ get keys() {
820
+ return ['hash', 'has']
908
821
  }
909
822
 
910
- fromBs58(input) {
911
- this.encoded = bs58__default["default"].decode(input);
912
- this.decode();
823
+ constructor(data) {
824
+ const name = 'peernet-dht-response';
825
+ super(data, protons__default["default"](proto$8).PeernetDHTMessageResponse, {name});
913
826
  }
914
-
915
- getCodec(name) {
916
- return this.codecs[name].codec
827
+ }
828
+
829
+ var proto$7 = `
830
+ // PeernetDataMessage
831
+ message PeernetDataMessage {
832
+ required string hash = 1;
833
+ optional string store = 2;
834
+ }
835
+ `;
836
+
837
+ /**
838
+ * @extends {CodecFormat}
839
+ */
840
+ class DataMessage extends codecFormatInterface.FormatInterface {
841
+ get keys() {
842
+ return ['hash', 'store']
917
843
  }
918
-
919
- getCodecName(codec) {
920
- return Object.keys(this.codecs).reduce((p, c) => {
921
- const item = this.codecs[c];
922
- if (item.codec === codec) return c;
923
- else return p;
924
- }, undefined)
844
+ /**
845
+ * @param {Buffer|String|Object|DataMessage} data - The data needed to create the DataMessage
846
+ */
847
+ constructor(data) {
848
+ super(data, protons__default["default"](proto$7).PeernetDataMessage, {name: 'peernet-data'});
925
849
  }
926
-
927
- getHashAlg(name) {
928
- return this.codecs[name].hashAlg
850
+ }
851
+
852
+ var proto$6 = `
853
+ // PsMessage
854
+ message PsMessage {
855
+ required bytes data = 1;
856
+ required bytes topic = 2;
857
+ }`;
858
+
859
+ class PsMessage extends codecFormatInterface.FormatInterface {
860
+ get keys() {
861
+ return ['data', 'topic']
929
862
  }
930
863
 
931
- fromCodec(codec) {
932
- this.name = this.getCodecName(codec);
933
- this.hashAlg = this.getHashAlg(this.name);
934
-
935
- this.codec = this.getCodec(this.name);
936
- this.codecBuffer = varint__default["default"].encode(codec);
864
+ constructor(buffer) {
865
+ const name = 'peernet-ps';
866
+ super(buffer, protons__default["default"](proto$6).PsMessage, {name});
937
867
  }
938
-
939
- fromName(name) {
940
- const codec = this.getCodec(name);
941
- this.name = name;
942
- this.codec = codec;
943
- this.hashAlg = this.getHashAlg(name);
944
- this.codecBuffer = varint__default["default"].encode(codec);
868
+ }
869
+
870
+ var proto$5 = `
871
+ // PeernetPeerMessage
872
+ message PeernetPeerMessage {
873
+ required string id = 1;
874
+ }
875
+ `;
876
+
877
+ class PeerMessage extends codecFormatInterface.FormatInterface {
878
+ get keys() {
879
+ return ['id']
945
880
  }
946
881
 
947
- toBs32() {
948
- this.encode();
949
- return bs32__default["default"].encode(this.encoded)
882
+ constructor(data) {
883
+ const name = 'peernet-peer';
884
+ super(data, protons__default["default"](proto$5).PeernetPeerMessage, {name});
950
885
  }
951
-
952
- toBs58() {
953
- this.encode();
954
- return bs58__default["default"].encode(this.encoded)
886
+ }
887
+
888
+ var proto$4 = `
889
+ // PeernetRequestMessage
890
+ message PeernetRequestMessage {
891
+ required string request = 1;
892
+ }
893
+ `;
894
+
895
+ class RequestMessage extends codecFormatInterface.FormatInterface {
896
+ get keys() {
897
+ return ['request']
955
898
  }
956
899
 
957
- toHex() {
958
- return this.encoded.toString('hex')
900
+ constructor(data) {
901
+ const name = 'peernet-request';
902
+ super(data, protons__default["default"](proto$4).PeernetRequestMessage, {name});
959
903
  }
960
-
961
- decode() {
962
- const codec = varint__default["default"].decode(this.encoded);
963
- this.fromCodec(codec);
904
+ }
905
+
906
+ var proto$3 = `
907
+ // PeernetResponseMessage
908
+ message PeernetResponseMessage {
909
+ required bytes response = 1;
910
+ }
911
+ `;
912
+
913
+ class ResponseMessage extends codecFormatInterface.FormatInterface {
914
+ get keys() {
915
+ return ['response']
964
916
  }
965
917
 
966
- encode() {
967
- const codec = varint__default["default"].encode(this.decoded);
968
- this.encoded = codec;
969
- return this.encoded
918
+ constructor(data) {
919
+ const name = 'peernet-response';
920
+ super(data, protons__default["default"](proto$3).PeernetResponseMessage, {name});
970
921
  }
971
922
  }
972
923
 
973
- class PeernetHash {
974
- constructor(buffer, options = {}) {
975
- if (options.name) this.name = options.name;
976
- else this.name = 'disco-hash';
977
- if (options.codecs) this.codecs = options.codecs;
978
- if (buffer) {
979
- if (buffer instanceof Uint8Array) {
980
- this.discoCodec = new PeernetCodec(buffer, this.codecs);
981
- const name = this.discoCodec.name;
982
-
983
- if (name) {
984
- this.name = name;
985
- this.decode(buffer);
986
- } else {
987
- this.encode(buffer);
988
- }
989
- }
990
-
991
- if (typeof buffer === 'string') {
992
- if (isHex__default["default"](buffer)) this.fromHex(buffer);
993
- if (bs32__default["default"].isBase32(buffer)) this.fromBs32(buffer);
994
- else if (bs58__default["default"].isBase58(buffer)) this.fromBs58(buffer);
995
- else throw new Error(`unsupported string ${buffer}`)
996
- } else if (typeof buffer === 'object') this.fromJSON(buffer);
997
- }
924
+ var proto$2 = `
925
+ // PeernetPeerMessageResponse
926
+ message PeernetPeerMessageResponse {
927
+ required string id = 1;
928
+ }
929
+ `;
930
+
931
+ class PeerMessageResponse extends codecFormatInterface.FormatInterface {
932
+ get keys() {
933
+ return ['id']
998
934
  }
999
935
 
1000
- get prefix() {
1001
- const length = this.length;
1002
- const uint8Array = new Uint8Array(length.length + this.discoCodec.codecBuffer.length);
1003
- uint8Array.set(length);
1004
- uint8Array.set(this.discoCodec.codecBuffer, length.length);
1005
-
1006
- return uint8Array
936
+ constructor(data) {
937
+ const name = 'peernet-peer-response';
938
+ super(data, protons__default["default"](proto$2).PeernetPeerMessageResponse, {name});
1007
939
  }
1008
-
1009
- get length() {
1010
- return varint__default["default"].encode(this.size)
940
+ }
941
+
942
+ var proto$1 = `
943
+ // PeernetDataMessageResponse
944
+ message PeernetDataMessageResponse {
945
+ required string hash = 1;
946
+ required bytes data = 2;
947
+ }
948
+ `;
949
+
950
+ class DataMessageResponse extends codecFormatInterface.FormatInterface {
951
+ get keys() {
952
+ return ['hash', 'data']
1011
953
  }
1012
954
 
1013
- get buffer() {
1014
- return this.hash
955
+ constructor(data) {
956
+ const name = 'peernet-data-response';
957
+ super(data, protons__default["default"](proto$1).PeernetDataMessageResponse, {name});
1015
958
  }
1016
-
1017
- toHex() {
1018
- return this.hash.toString('hex')
959
+ }
960
+
961
+ var proto = `
962
+ message ChatMessage {
963
+ required string value = 1;
964
+ required string author = 2;
965
+ required uint64 timestamp = 3;
966
+ repeated string files = 4;
967
+ }`;
968
+
969
+ class ChatMessage extends codecFormatInterface.FormatInterface {
970
+ get keys() {
971
+ return ['author', 'value', 'timestamp', 'files']
1019
972
  }
1020
973
 
1021
- fromHex(hex) {
1022
- return this.decode(Buffer.from(hex, 'hex'))
974
+ constructor(buffer) {
975
+ const name = 'chat-message';
976
+ super(buffer, protons__default["default"](proto).ChatMessage, {name});
1023
977
  }
978
+ }
979
+
980
+ const protoFor = (data) => {
981
+ if (!Buffer.isBuffer(data)) data = Buffer.from(data);
982
+ const codec = new codecFormatInterface.Codec(data);
983
+ if (!codec.name) throw new Error('proto not found')
984
+ const Proto = globalThis.peernet.protos[codec.name];
985
+ if (!Proto) throw (new Error(`No proto defined for ${codec.name}`))
986
+ return new Proto(data)
987
+ };
1024
988
 
1025
- fromJSON(json) {
1026
- return this.encode(Buffer.from(JSON.stringify(json)))
989
+ /**
990
+ * wether or not a peernet daemon is active
991
+ * @return {Boolean}
992
+ */
993
+ const hasDaemon = async () => {
994
+ try {
995
+ let response = await fetch('http://127.0.0.1:1000/api/version');
996
+ response = await response.json();
997
+ return Boolean(response.client === '@peernet/api/http')
998
+ } catch (e) {
999
+ return false
1027
1000
  }
1001
+ };
1028
1002
 
1029
- toBs32() {
1030
- return bs32__default["default"].encode(this.hash)
1031
- }
1003
+ const https = () => {
1004
+ if (!globalThis.location) return false;
1005
+ return Boolean(globalThis.location.protocol === 'https:')
1006
+ };
1032
1007
 
1033
- fromBs32(bs) {
1034
- return this.decode(bs32__default["default"].decode(bs))
1008
+ /**
1009
+ * Get current environment
1010
+ * @return {String} current environment [node, electron, browser]
1011
+ */
1012
+ const environment = () => {
1013
+ const _navigator = globalThis.navigator;
1014
+ if (!_navigator) {
1015
+ return 'node'
1016
+ } else if (_navigator && /electron/i.test(_navigator.userAgent)) {
1017
+ return 'electron'
1018
+ } else {
1019
+ return 'browser'
1035
1020
  }
1021
+ };
1036
1022
 
1037
- toBs58() {
1038
- return bs58__default["default"].encode(this.hash)
1039
- }
1023
+ /**
1024
+ * * Get current environment
1025
+ * @return {Object} result
1026
+ * @property {Boolean} reult.daemon whether or not daemon is running
1027
+ * @property {Boolean} reult.environment Current environment
1028
+ */
1029
+ const target = async () => {
1030
+ let daemon = false;
1031
+ const env = await environment();
1032
+ if (!https()) daemon = await hasDaemon();
1040
1033
 
1041
- fromBs58(bs) {
1042
- return this.decode(bs58__default["default"].decode(bs))
1034
+ return {daemon, environment: env}
1035
+ };
1036
+
1037
+ class PeerDiscovery {
1038
+ constructor(id) {
1039
+ this.id = id;
1043
1040
  }
1044
1041
 
1045
- toString(encoding = 'utf8') {
1046
- return this.hash.toString(encoding)
1047
- }
1042
+ _getPeerId(id) {
1043
+ if (!peernet.peerMap || peernet.peerMap && peernet.peerMap.size === 0) return false
1048
1044
 
1049
- encode(buffer, name) {
1050
- if (!this.name && name) this.name = name;
1051
- if (!buffer) buffer = this.buffer;
1052
- this.discoCodec = new PeernetCodec(this.name, this.codecs);
1053
- this.discoCodec.fromName(this.name);
1054
- let hashAlg = this.discoCodec.hashAlg;
1055
- if (hashAlg.includes('dbl')) {
1056
- hashAlg = hashAlg.replace('dbl-', '');
1057
- buffer = createKeccakHash__default["default"](hashAlg.replace('-', '')).update(buffer).digest();
1045
+ for (const entry of [...peernet.peerMap.entries()]) {
1046
+ for (const _id of entry[1]) {
1047
+ if (_id === id) return entry[0]
1048
+ }
1058
1049
  }
1059
- this.digest = createKeccakHash__default["default"](hashAlg.replace('-', '')).update(buffer).digest();
1060
- this.size = this.digest.length;
1050
+ }
1061
1051
 
1062
- this.codec = this.discoCodec.encode();
1063
- this.codec = this.discoCodec.codecBuffer;
1064
- const uint8Array = new Uint8Array(this.digest.length + this.prefix.length);
1065
- uint8Array.set(this.prefix);
1066
- uint8Array.set(this.digest, this.prefix.length);
1052
+ async discover(peer) {
1053
+ let id = this._getPeerId(peer.id);
1054
+ if (id) return id
1055
+ const data = new peernet.protos['peernet-peer']({id: this.id});
1056
+ const node = await peernet.prepareMessage(peer.id, data.encoded);
1067
1057
 
1068
- this.hash = uint8Array;
1058
+ let response = await peer.request(node.encoded);
1059
+ response = protoFor(response);
1060
+ response = new peernet.protos['peernet-peer-response'](response.decoded.data);
1069
1061
 
1070
- return this.hash
1071
- }
1062
+ id = response.decoded.id;
1063
+ if (id === this.id) return;
1072
1064
 
1073
- validate(buffer) {
1074
- if (Buffer.isBuffer(buffer)) {
1075
- const codec = varint__default["default"].decode(buffer);
1076
- if (this.codecs[codec]) {
1077
- this.decode(buffer);
1078
- } else {
1079
- this.encode(buffer);
1065
+ if (!peernet.peerMap.has(id)) peernet.peerMap.set(id, [peer.id]);
1066
+ else {
1067
+ const connections = peernet.peerMap.get(id);
1068
+ if (connections.indexOf(peer.id) === -1) {
1069
+ connections.push(peer.id);
1070
+ peernet.peerMap.set(peer.id, connections);
1080
1071
  }
1081
1072
  }
1082
- if (typeof buffer === 'string') {
1083
- if (isHex__default["default"](buffer)) this.fromHex(buffer);
1084
- if (bs32__default["default"].test(buffer)) this.fromBs32(buffer);
1085
- }
1086
- if (typeof buffer === 'object') this.fromJSON(buffer);
1073
+ return id
1087
1074
  }
1088
1075
 
1089
- decode(buffer) {
1090
- this.hash = buffer;
1091
- const codec = varint__default["default"].decode(buffer);
1092
-
1093
- this.discoCodec = new PeernetCodec(codec, this.codecs);
1094
- // TODO: validate codec
1095
- buffer = buffer.slice(varint__default["default"].decode.bytes);
1096
- this.size = varint__default["default"].decode(buffer);
1097
- this.digest = buffer.slice(varint__default["default"].decode.bytes);
1098
- if (this.digest.length !== this.size) {
1099
- throw new Error(`hash length inconsistent: 0x${this.hash.toString('hex')}`)
1100
- }
1101
-
1102
- // const discoCodec = new Codec(codec, this.codecs)
1103
-
1104
- this.name = this.discoCodec.name;
1076
+ async discoverHandler(message, peer) {
1077
+ const {id, proto} = message;
1078
+ // if (typeof message.data === 'string') message.data = Buffer.from(message.data)
1079
+ if (proto.name === 'peernet-peer') {
1080
+ const from = proto.decoded.id;
1081
+ if (from === this.id) return;
1105
1082
 
1083
+ if (!peernet.peerMap.has(from)) peernet.peerMap.set(from, [peer.id]);
1084
+ else {
1085
+ const connections = peernet.peerMap.get(from);
1086
+ if (connections.indexOf(peer.id) === -1) {
1087
+ connections.push(peer.id);
1088
+ peernet.peerMap.set(from, connections);
1089
+ }
1090
+ }
1091
+ const data = new peernet.protos['peernet-peer-response']({id: this.id});
1092
+ const node = await peernet.prepareMessage(from, data.encoded);
1106
1093
 
1107
- this.size = this.digest.length;
1094
+ peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
1095
+ } else if (proto.name === 'peernet-peer-response') {
1096
+ const from = proto.decoded.id;
1097
+ if (from === this.id) return;
1108
1098
 
1109
- return {
1110
- codec: this.codec,
1111
- name: this.name,
1112
- size: this.size,
1113
- length: this.length,
1114
- digest: this.digest,
1099
+ if (!peernet.peerMap.has(from)) peernet.peerMap.set(from, [peer.id]);
1100
+ else {
1101
+ const connections = peernet.peerMap.get(from);
1102
+ if (connections.indexOf(peer.id) === -1) {
1103
+ connections.push(peer.id);
1104
+ peernet.peerMap.set(from, connections);
1105
+ }
1106
+ }
1115
1107
  }
1116
1108
  }
1117
1109
  }
1118
1110
 
1119
- class FormatInterface {
1120
- /**
1121
- * @param {Buffer|String|Object} buffer - data - The data needed to create the desired message
1122
- * @param {Object} proto - {encode, decode}
1123
- * @param {Object} options - {hashFormat, name}
1124
- */
1125
- constructor(buffer, proto, options = {}) {
1126
- this.protoEncode = proto.encode;
1127
- this.protoDecode = proto.decode;
1128
- this.hashFormat = options.hashFormat || 'bs32';
1129
- if (options.name) this.name = options.name;
1130
- if (buffer instanceof Uint8Array) this.fromUint8Array(buffer);
1131
- else if (buffer instanceof ArrayBuffer) this.fromArrayBuffer(buffer);
1132
- else if (buffer.name === options.name) return buffer
1133
- else if (buffer instanceof String) {
1134
- if (isHex__default["default"](buffer)) this.fromHex(buffer);
1135
- else if (bs32__default["default"].isBase32(buffer)) this.fromBs32(buffer);
1136
- else if (bs58__default["default"].isBase58(buffer)) this.fromBs58(buffer);
1137
- else throw new Error(`unsupported string ${buffer}`)
1138
- } else {
1139
- this.create(buffer);
1140
- }
1141
- }
1111
+ /**
1112
+ * Keep history of fetched address and ptr
1113
+ * @property {Object} address
1114
+ * @property {Object} ptr
1115
+ */
1116
+ const lastFetched = {
1117
+ address: {
1118
+ value: undefined,
1119
+ timestamp: 0,
1120
+ },
1121
+ ptr: {
1122
+ value: undefined,
1123
+ timestamp: 0,
1124
+ },
1125
+ };
1142
1126
 
1143
- /**
1144
- * @return {PeernetHash}
1145
- */
1146
- get peernetHash() {
1147
- return new PeernetHash(this.decoded, {name: this.name})
1127
+ const getAddress = async () => {
1128
+ const {address} = lastFetched;
1129
+ const now = Math.round(new Date().getTime() / 1000);
1130
+ if (now - address.timestamp > 1200000) {
1131
+ address.value = await fetch('https://icanhazip.com/');
1132
+ address.value = await address.value.text();
1133
+ address.timestamp = Math.round(new Date().getTime() / 1000);
1134
+ lastFetched.address = address;
1148
1135
  }
1149
1136
 
1150
- /**
1151
- * @return {peernetHash}
1152
- */
1153
- get hash() {
1154
- const upper = this.hashFormat.charAt(0).toUpperCase();
1155
- const format = `${upper}${this.hashFormat.substring(1, this.hashFormat.length)}`;
1156
- return this.peernetHash[`to${format}`]()
1157
- }
1137
+ return address.value
1138
+ };
1158
1139
 
1159
- /**
1160
- * @return {Object}
1161
- */
1162
- decode() {
1163
- let encoded = this.encoded;
1164
- const discoCodec = new PeernetCodec(this.encoded);
1165
- encoded = encoded.slice(discoCodec.codecBuffer.length);
1166
- this.name = discoCodec.name;
1167
- this.decoded = this.protoDecode(encoded);
1168
- return this.decoded
1169
- }
1140
+ const degreesToRadians = (degrees) => {
1141
+ return degrees * Math.PI / 180;
1142
+ };
1170
1143
 
1171
- /**
1172
- * @return {Buffer}
1173
- */
1174
- encode(decoded) {
1175
- if (!decoded) decoded = this.decoded;
1176
- const codec = new PeernetCodec(this.name);
1177
- const encoded = this.protoEncode(decoded);
1178
- const uint8Array = new Uint8Array(encoded.length + codec.codecBuffer.length);
1179
- uint8Array.set(codec.codecBuffer);
1180
- uint8Array.set(encoded, codec.codecBuffer.length);
1181
- this.encoded = uint8Array;
1182
- return this.encoded
1183
- }
1184
-
1185
- hasCodec() {
1186
- if (!this.encoded) return false
1187
- const codec = new PeernetCodec(this.encoded);
1188
- if (codec.name) return true
1189
- }
1190
-
1191
- fromUint8Array(buffer) {
1192
- this.encoded = buffer;
1193
- if (!this.hasCodec()) this.create(
1194
- JSON.parse(new TextDecoder().decode(this.encoded))
1195
- );
1196
- else this.decode();
1197
- }
1198
-
1199
- fromArrayBuffer(buffer) {
1200
- this.encoded = new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength);
1201
- if (!this.hasCodec()) this.create(
1202
- JSON.parse(new TextDecoder().decode(this.encoded))
1203
- );
1204
- else this.decode();
1205
- }
1206
-
1207
- toString() {
1208
- return this.encoded.toString()
1209
- }
1210
-
1211
- async toArray() {
1212
- const array = [];
1213
- for await (const value of this.encoded.values()) {
1214
- array.push(value);
1215
- }
1216
- return array
1217
- }
1144
+ const distanceInKmBetweenEarthCoordinates = (lat1, lon1, lat2, lon2) => {
1145
+ const earthRadiusKm = 6371;
1218
1146
 
1219
- fromString(string) {
1220
- this.encoded = new Uint8Array(string.split(','));
1221
- this.decode();
1222
- }
1147
+ const dLat = degreesToRadians(lat2-lat1);
1148
+ const dLon = degreesToRadians(lon2-lon1);
1223
1149
 
1224
- fromArray(array) {
1225
- this.encoded = new Uint8Array([...array]);
1226
- this.decode();
1227
- }
1150
+ lat1 = degreesToRadians(lat1);
1151
+ lat2 = degreesToRadians(lat2);
1152
+ const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
1153
+ Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
1154
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
1155
+ return earthRadiusKm * c;
1156
+ };
1228
1157
 
1158
+ class DhtEarth {
1229
1159
  /**
1230
- * @param {Buffer} encoded
1160
+ *
1231
1161
  */
1232
- fromEncoded(encoded) {
1233
- this.encoded = encoded;
1234
- this.decode();
1162
+ constructor() {
1163
+ this.providerMap = new Map();
1235
1164
  }
1236
1165
 
1237
1166
  /**
1238
- * @param {String} encoded
1167
+ * @param {Object} address
1168
+ * @return {Object} {latitude: lat, longitude: lon}
1239
1169
  */
1240
- fromHex(encoded) {
1241
- this.encoded = Buffer.from(encoded, 'hex');
1242
- this.decode();
1170
+ async getCoordinates(address) {
1171
+ // const {address} = parseAddress(provider)
1172
+ const request = `https://whereis.leofcoin.org/?ip=${address}`;
1173
+ let response = await fetch(request);
1174
+ response = await response.json();
1175
+ const {lat, lon} = response;
1176
+ return {latitude: lat, longitude: lon}
1243
1177
  }
1244
1178
 
1245
1179
  /**
1246
- * @param {String} encoded
1180
+ * @param {Object} peer
1181
+ * @param {Object} provider
1182
+ * @return {Object} {provider, distance}
1247
1183
  */
1248
- fromBs32(encoded) {
1249
- this.encoded = bs32__default["default"].decode(encoded);
1250
- this.decode();
1184
+ async getDistance(peer, provider) {
1185
+ const {latitude, longitude} = await this.getCoordinates(provider.address);
1186
+ return {provider, distance: distanceInKmBetweenEarthCoordinates(peer.latitude, peer.longitude, latitude, longitude)}
1251
1187
  }
1252
1188
 
1253
1189
  /**
1254
- * @param {String} encoded
1190
+ * @param {Array} providers
1191
+ * @return {Object} closestPeer
1255
1192
  */
1256
- fromBs58(encoded) {
1257
- this.encoded = bs58__default["default"].decode(encoded);
1258
- this.decode();
1259
- }
1193
+ async closestPeer(providers) {
1194
+ let all = [];
1195
+ const address = await getAddress();
1196
+ const peerLoc = await this.getCoordinates(address);
1260
1197
 
1261
- /**
1262
- * @return {String} encoded
1263
- */
1264
- toHex() {
1265
- if (!this.encoded) this.encode();
1266
- return this.encoded.toString('hex')
1267
- }
1198
+ for (const provider of providers) {
1199
+ if (provider.address === '127.0.0.1') all.push({provider, distance: 0});
1200
+ else all.push(this.getDistance(peerLoc, provider));
1201
+ }
1268
1202
 
1269
- /**
1270
- * @return {String} encoded
1271
- */
1272
- toBs32() {
1273
- if (!this.encoded) this.encode();
1274
- return bs32__default["default"].encode(this.encoded)
1203
+ all = await Promise.all(all);
1204
+ all = all.sort((previous, current) => previous.distance - current.distance);
1205
+ return all[0].provider;
1275
1206
  }
1276
1207
 
1277
1208
  /**
1278
- * @return {String} encoded
1209
+ * @param {String} hash
1210
+ * @return {Array} providers
1279
1211
  */
1280
- toBs58() {
1281
- if (!this.encoded) this.encode();
1282
- return bs58__default["default"].encode(this.encoded)
1212
+ providersFor(hash) {
1213
+ return this.providerMap.get(hash);
1283
1214
  }
1284
1215
 
1285
1216
  /**
1286
- * @param {Object} data
1217
+ * @param {String} address
1218
+ * @param {String} hash
1219
+ * @return {Array} providers
1287
1220
  */
1288
- create(data) {
1289
- const decoded = {};
1290
- if (this.keys?.length > 0) {
1291
- for (const key of this.keys) {
1292
- Object.defineProperties(decoded, {
1293
- [key]: {
1294
- enumerable: true,
1295
- configurable: true,
1296
- set: (val) => value = data[key],
1297
- get: () => data[key]
1298
- }
1299
- });
1300
- }
1301
-
1302
- this.decoded = decoded;
1303
- this.encode();
1304
- }
1305
- }
1306
- }
1307
-
1308
- class PeernetMessage extends FormatInterface {
1309
- get keys() {
1310
- return ['data', 'signature', 'from', 'to', 'id']
1311
- }
1221
+ async addProvider(address, hash) {
1222
+ let providers = [];
1223
+ if (this.providerMap.has(hash)) providers = this.providerMap.get(hash);
1312
1224
 
1313
- constructor(buffer) {
1314
- const name = 'peernet-message';
1315
- super(buffer, protons__default["default"](proto$a).PeernetMessage, {name});
1225
+ providers = new Set([...providers, address]);
1226
+ this.providerMap.set(hash, providers);
1227
+ return providers;
1316
1228
  }
1317
1229
  }
1318
1230
 
1319
- var proto$9 = `
1320
- // PeernetDHTMessage
1321
- message PeernetDHTMessage {
1322
- required string hash = 1;
1323
- optional string store = 2;
1324
- }
1325
- `;
1326
-
1327
1231
  /**
1328
- * @example `
1329
- new DHTMessage(hash, store)
1330
- // store = optional if not set, peernet checks every store
1331
- let message = new DHTMessage('hashmvbs124xcfd...', 'transaction')
1332
- message = new DHTMessage('hashmvbs124xcfd...', 'block')
1333
- `
1232
+ * @params {String} network
1233
+ * @return {object} { identity, accounts, config }
1334
1234
  */
1335
- class DHTMessage extends FormatInterface {
1336
- /**
1337
- *
1338
- */
1339
- get keys() {
1340
- return ['hash', 'store']
1341
- }
1235
+ var generateAccount = async network => {
1236
+ let wallet = new MultiWallet__default["default"](network);
1237
+ /**
1238
+ * @type {string}
1239
+ */
1240
+ const mnemonic = await wallet.generate();
1342
1241
 
1343
- constructor(data) {
1344
- const name = 'peernet-dht';
1345
- super(data, protons__default["default"](proto$9).PeernetDHTMessage, {name});
1346
- }
1347
- }
1348
-
1349
- var proto$8 = `
1350
- // PeernetDHTMessageResponse
1351
- message PeernetDHTMessageResponse {
1352
- required string hash = 1;
1353
- required bool has = 2;
1354
- }
1355
- `;
1242
+ wallet = new MultiWallet__default["default"](network);
1243
+ await wallet.recover(mnemonic, network);
1244
+ /**
1245
+ * @type {object}
1246
+ */
1247
+ const account = wallet.account(0);
1248
+ /**
1249
+ * @type {object}
1250
+ */
1251
+ const external = account.external(0);
1252
+ const internal = account.internal(0);
1253
+
1254
+ return {
1255
+ identity: {
1256
+ mnemonic,
1257
+ // multiWIF: wallet.export(),
1258
+ publicKey: external.publicKey,
1259
+ privateKey: external.privateKey,
1260
+ walletId: external.id
1261
+ },
1262
+ accounts: [['main account', external.address, internal.address]]
1263
+ // config: {
1264
+ // }
1265
+ }
1266
+ };
1356
1267
 
1357
- class DHTMessageResponse extends FormatInterface {
1358
- get keys() {
1359
- return ['hash', 'has']
1268
+ var testnets = {
1269
+ 'leofcoin:olivia': {
1270
+ messagePrefix: '\u0019Leofcoin Signed Message:',
1271
+ pubKeyHash: 0x73, // o
1272
+ scriptHash: 0x76, // p
1273
+ multiTxHash: 0x8b4125, // omtx
1274
+ payments: {
1275
+ version: 0,
1276
+ unspent: 0x1fa443d7 // ounsp
1277
+ },
1278
+ wif: 0x7D, // s
1279
+ multiCodec: 0x7c4,
1280
+ bip32: { public: 0x13BBF2D5, private: 0x13BBCBC5 }
1281
+ },
1282
+ 'bitcoin:testnet': {
1283
+ messagePrefix: '\x18Bitcoin Signed Message:\n',
1284
+ bech32: 'tb',
1285
+ pubKeyHash: 0x6f,
1286
+ scriptHash: 0xc4,
1287
+ wif: 0xef,
1288
+ bip32: {
1289
+ public: 0x043587cf,
1290
+ private: 0x04358394
1291
+ }
1360
1292
  }
1361
1293
 
1362
- constructor(data) {
1363
- const name = 'peernet-dht-response';
1364
- super(data, protons__default["default"](proto$8).PeernetDHTMessageResponse, {name});
1365
- }
1366
- }
1367
-
1368
- var proto$7 = `
1369
- // PeernetDataMessage
1370
- message PeernetDataMessage {
1371
- required string hash = 1;
1372
- optional string store = 2;
1373
- }
1374
- `;
1294
+ };
1375
1295
 
1296
+ // https://en.bitcoin.it/wiki/List_of_address_prefixes
1376
1297
  /**
1377
- * @extends {CodecFormat}
1298
+ * Main network
1299
+ * @return {messagePrefix, pubKeyHash, scriptHash, wif, bip32}
1378
1300
  */
1379
- class DataMessage extends FormatInterface {
1380
- get keys() {
1381
- return ['hash', 'store']
1382
- }
1383
- /**
1384
- * @param {Buffer|String|Object|DataMessage} data - The data needed to create the DataMessage
1385
- */
1386
- constructor(data) {
1387
- super(data, protons__default["default"](proto$7).PeernetDataMessage, {name: 'peernet-data'});
1388
- }
1389
- }
1390
-
1391
- var proto$6 = `
1392
- // PsMessage
1393
- message PsMessage {
1394
- required bytes data = 1;
1395
- required bytes topic = 2;
1396
- }`;
1397
-
1398
- class PsMessage extends FormatInterface {
1399
- get keys() {
1400
- return ['data', 'topic']
1401
- }
1402
-
1403
- constructor(buffer) {
1404
- const name = 'peernet-ps';
1405
- super(buffer, protons__default["default"](proto$6).PsMessage, {name});
1406
- }
1407
- }
1408
-
1409
- var proto$5 = `
1410
- // PeernetPeerMessage
1411
- message PeernetPeerMessage {
1412
- required string id = 1;
1413
- }
1414
- `;
1415
-
1416
- class PeerMessage extends FormatInterface {
1417
- get keys() {
1418
- return ['id']
1419
- }
1420
-
1421
- constructor(data) {
1422
- const name = 'peernet-peer';
1423
- super(data, protons__default["default"](proto$5).PeernetPeerMessage, {name});
1424
- }
1425
- }
1426
-
1427
- var proto$4 = `
1428
- // PeernetRequestMessage
1429
- message PeernetRequestMessage {
1430
- required string request = 1;
1431
- }
1432
- `;
1433
-
1434
- class RequestMessage extends FormatInterface {
1435
- get keys() {
1436
- return ['request']
1437
- }
1438
-
1439
- constructor(data) {
1440
- const name = 'peernet-request';
1441
- super(data, protons__default["default"](proto$4).PeernetRequestMessage, {name});
1442
- }
1443
- }
1444
-
1445
- var proto$3 = `
1446
- // PeernetResponseMessage
1447
- message PeernetResponseMessage {
1448
- required bytes response = 1;
1449
- }
1450
- `;
1451
-
1452
- class ResponseMessage extends FormatInterface {
1453
- get keys() {
1454
- return ['response']
1455
- }
1456
-
1457
- constructor(data) {
1458
- const name = 'peernet-response';
1459
- super(data, protons__default["default"](proto$3).PeernetResponseMessage, {name});
1460
- }
1461
- }
1462
-
1463
- var proto$2 = `
1464
- // PeernetPeerMessageResponse
1465
- message PeernetPeerMessageResponse {
1466
- required string id = 1;
1467
- }
1468
- `;
1469
-
1470
- class PeerMessageResponse extends FormatInterface {
1471
- get keys() {
1472
- return ['id']
1473
- }
1474
-
1475
- constructor(data) {
1476
- const name = 'peernet-peer-response';
1477
- super(data, protons__default["default"](proto$2).PeernetPeerMessageResponse, {name});
1478
- }
1479
- }
1480
-
1481
- var proto$1 = `
1482
- // PeernetDataMessageResponse
1483
- message PeernetDataMessageResponse {
1484
- required string hash = 1;
1485
- required bytes data = 2;
1486
- }
1487
- `;
1488
-
1489
- class DataMessageResponse extends FormatInterface {
1490
- get keys() {
1491
- return ['hash', 'data']
1492
- }
1493
-
1494
- constructor(data) {
1495
- const name = 'peernet-data-response';
1496
- super(data, protons__default["default"](proto$1).PeernetDataMessageResponse, {name});
1497
- }
1498
- }
1499
-
1500
- var proto = `
1501
- message ChatMessage {
1502
- required string value = 1;
1503
- required string author = 2;
1504
- required uint64 timestamp = 3;
1505
- repeated string files = 4;
1506
- }`;
1507
-
1508
- class ChatMessage extends FormatInterface {
1509
- get keys() {
1510
- return ['author', 'value', 'timestamp', 'files']
1511
- }
1512
-
1513
- constructor(buffer) {
1514
- const name = 'chat-message';
1515
- super(buffer, protons__default["default"](proto).ChatMessage, {name});
1516
- }
1517
- }
1518
-
1519
- const protoFor = (data) => {
1520
- if (!Buffer.isBuffer(data)) data = Buffer.from(data);
1521
- const codec = new PeernetCodec(data);
1522
- if (!codec.name) throw new Error('proto not found')
1523
- const Proto = globalThis.peernet.protos[codec.name];
1524
- if (!Proto) throw (new Error(`No proto defined for ${codec.name}`))
1525
- return new Proto(data)
1301
+ const leofcoin = {
1302
+ messagePrefix: '\u0019Leofcoin Signed Message:',
1303
+ pubKeyHash: 0x30, // L
1304
+ scriptHash: 0x37, // P
1305
+ multiTxHash: 0x3adeed, // Lmtx
1306
+ payments: {
1307
+ version: 0,
1308
+ unspent: 0x0d6e0327 // Lunsp
1309
+ },
1310
+ coin_type: 640,
1311
+ wif: 0x3F, // S
1312
+ multiCodec: 0x3c4,
1313
+ bip32: { public: 0x13BBF2D4, private: 0x13BBCBC4 },
1314
+ testnet: testnets['leofcoin:olivia']
1526
1315
  };
1527
1316
 
1528
- /**
1529
- * wether or not a peernet daemon is active
1530
- * @return {Boolean}
1531
- */
1532
- const hasDaemon = async () => {
1533
- try {
1534
- let response = await fetch('http://127.0.0.1:1000/api/version');
1535
- response = await response.json();
1536
- return Boolean(response.client === '@peernet/api/http')
1537
- } catch (e) {
1538
- return false
1539
- }
1317
+ const bitcoin = {
1318
+ messagePrefix: '\x18Bitcoin Signed Message:\n',
1319
+ bech32: 'bc',
1320
+ pubKeyHash: 0x00,
1321
+ multiCodec: 0x00,
1322
+ scriptHash: 0x05,
1323
+ wif: 0x80,
1324
+ coin_type: 0,
1325
+ bip32: {
1326
+ public: 0x0488b21e, private: 0x0488ade4
1327
+ },
1328
+ testnet: testnets['bitcoin:testnet']
1540
1329
  };
1541
1330
 
1542
- const https = () => {
1543
- if (!globalThis.location) return false;
1544
- return Boolean(globalThis.location.protocol === 'https:')
1331
+ const litecoin = {
1332
+ messagePrefix: '\x19Litecoin Signed Message:\n',
1333
+ pubKeyHash: 0x30,
1334
+ scriptHash: 0x32,
1335
+ wif: 0xb0,
1336
+ bip32: {
1337
+ public: 0x019da462,
1338
+ private: 0x019d9cfe
1339
+ }
1545
1340
  };
1546
1341
 
1547
- /**
1548
- * Get current environment
1549
- * @return {String} current environment [node, electron, browser]
1550
- */
1551
- const environment = () => {
1552
- const _navigator = globalThis.navigator;
1553
- if (!_navigator) {
1554
- return 'node'
1555
- } else if (_navigator && /electron/i.test(_navigator.userAgent)) {
1556
- return 'electron'
1557
- } else {
1558
- return 'browser'
1559
- }
1342
+ const ethereum = {
1343
+ messagePrefix: '\x19Ethereum Signed Message:\n',
1344
+ pubKeyHash: 0x30,
1345
+ scriptHash: 0x32,
1346
+ bip32: {
1347
+ private: 0x0488ADE4, public: 0x0488B21E
1348
+ },
1349
+ coin_type: 60,
1350
+ wif: 0x45,//E
1351
+ multiCodec: 0x3c5
1560
1352
  };
1561
1353
 
1562
1354
  /**
1563
- * * Get current environment
1564
- * @return {Object} result
1565
- * @property {Boolean} reult.daemon whether or not daemon is running
1566
- * @property {Boolean} reult.environment Current environment
1355
+ * Our & supported networks
1356
+ * @return {leofcoin, olivia}
1567
1357
  */
1568
- const target = async () => {
1569
- let daemon = false;
1570
- const env = await environment();
1571
- if (!https()) daemon = await hasDaemon();
1572
-
1573
- return {daemon, environment: env}
1358
+ var networks = {
1359
+ leofcoin,
1360
+ bitcoin,
1361
+ litecoin,
1362
+ ethereum
1574
1363
  };
1575
1364
 
1576
- class PeerDiscovery {
1577
- constructor(id) {
1578
- this.id = id;
1579
- }
1580
-
1581
- _getPeerId(id) {
1582
- if (!peernet.peerMap || peernet.peerMap && peernet.peerMap.size === 0) return false
1365
+ const fromNetworkString = network => {
1366
+ const parts = network.split(':');
1367
+ network = networks[parts[0]];
1368
+ if (parts[1]) {
1369
+ if (network[parts[1]]) network = network[parts[1]];
1583
1370
 
1584
- for (const entry of [...peernet.peerMap.entries()]) {
1585
- for (const _id of entry[1]) {
1586
- if (_id === id) return entry[0]
1587
- }
1588
- }
1371
+ network.coin_type = 1;
1589
1372
  }
1373
+ return network;
1374
+ };
1375
+
1376
+ // import { createHash } from 'crypto'
1377
+ // import { createHash as _createHash } from './hash'
1590
1378
 
1591
- async discover(peer) {
1592
- let id = this._getPeerId(peer.id);
1593
- if (id) return id
1594
- const data = new peernet.protos['peernet-peer']({id: this.id});
1595
- const node = await peernet.prepareMessage(peer.id, data.encoded);
1379
+ const { encode: encode$1, decode: decode$1 } = bs58check__default["default"];
1380
+ class HDWallet {
1596
1381
 
1597
- let response = await peer.request(node.encoded);
1598
- response = protoFor(response);
1599
- response = new peernet.protos['peernet-peer-response'](response.decoded.data);
1382
+ get chainCodeBuffer() {
1383
+ return this.ifNotLocked(() => this.hdnode.chainCode)
1384
+ }
1600
1385
 
1601
- id = response.decoded.id;
1602
- if (id === this.id) return;
1386
+ get chainCode() {
1387
+ return this.ifNotLocked(() => this.chainCodeBuffer.toString('hex'))
1388
+ }
1603
1389
 
1604
- if (!peernet.peerMap.has(id)) peernet.peerMap.set(id, [peer.id]);
1605
- else {
1606
- const connections = peernet.peerMap.get(id);
1607
- if (connections.indexOf(peer.id) === -1) {
1608
- connections.push(peer.id);
1609
- peernet.peerMap.set(peer.id, connections);
1610
- }
1611
- }
1612
- return id
1613
- }
1390
+ get privateKeyBuffer() {
1391
+ return this.ifNotLocked(() => this.hdnode.privateKey)
1392
+ }
1614
1393
 
1615
- async discoverHandler(message, peer) {
1616
- const {id, proto} = message;
1617
- // if (typeof message.data === 'string') message.data = Buffer.from(message.data)
1618
- if (proto.name === 'peernet-peer') {
1619
- const from = proto.decoded.id;
1620
- if (from === this.id) return;
1394
+ get privateKey() {
1395
+ return this.ifNotLocked(() => this.privateKeyBuffer.toString('hex'))
1396
+ }
1621
1397
 
1622
- if (!peernet.peerMap.has(from)) peernet.peerMap.set(from, [peer.id]);
1623
- else {
1624
- const connections = peernet.peerMap.get(from);
1625
- if (connections.indexOf(peer.id) === -1) {
1626
- connections.push(peer.id);
1627
- peernet.peerMap.set(from, connections);
1628
- }
1629
- }
1630
- const data = new peernet.protos['peernet-peer-response']({id: this.id});
1631
- const node = await peernet.prepareMessage(from, data.encoded);
1398
+ get publicKeyBuffer() {
1399
+ return this.ifNotLocked(() => this.hdnode.publicKey)
1400
+ }
1632
1401
 
1633
- peer.write(Buffer.from(JSON.stringify({id, data: node.encoded})));
1634
- } else if (proto.name === 'peernet-peer-response') {
1635
- const from = proto.decoded.id;
1636
- if (from === this.id) return;
1402
+ get publicKey() {
1403
+ return this.ifNotLocked(() => this.publicKeyBuffer.toString('hex'))
1404
+ }
1637
1405
 
1638
- if (!peernet.peerMap.has(from)) peernet.peerMap.set(from, [peer.id]);
1639
- else {
1640
- const connections = peernet.peerMap.get(from);
1641
- if (connections.indexOf(peer.id) === -1) {
1642
- connections.push(peer.id);
1643
- peernet.peerMap.set(from, connections);
1644
- }
1645
- }
1646
- }
1647
- }
1648
- }
1649
-
1650
- /**
1651
- * Keep history of fetched address and ptr
1652
- * @property {Object} address
1653
- * @property {Object} ptr
1654
- */
1655
- const lastFetched = {
1656
- address: {
1657
- value: undefined,
1658
- timestamp: 0,
1659
- },
1660
- ptr: {
1661
- value: undefined,
1662
- timestamp: 0,
1663
- },
1664
- };
1406
+ get ethereumAddress() {
1407
+ const buffer = ecc__default["default"].pointFromScalar(this.hdnode.__D, false);
1408
+ let hash = createKeccakHash__default["default"]('keccak256').update(buffer.slice(1)).digest();
1409
+ return `0x${hash.slice(-20).toString('hex')}`
1410
+ }
1665
1411
 
1666
- const getAddress = async () => {
1667
- const {address} = lastFetched;
1668
- const now = Math.round(new Date().getTime() / 1000);
1669
- if (now - address.timestamp > 1200000) {
1670
- address.value = await fetch('https://icanhazip.com/');
1671
- address.value = await address.value.text();
1672
- address.timestamp = Math.round(new Date().getTime() / 1000);
1673
- lastFetched.address = address;
1674
- }
1412
+ // async bitcoinAddress() {
1413
+ // const chainCode = this.privateKeyBuffer
1414
+ //
1415
+ // const node = bip32.fromPrivateKey(this.privateKeyBuffer, chainCode, networks['bitcoin'])
1416
+ // let buffer = await _createHash(node.publicKey, 'SHA-256')
1417
+ // buffer = createHash('ripemd160').update(buffer).digest()
1418
+ // // buffer = Buffer.from(`0x00${buffer.toString('hex')}`, 'hex')
1419
+ // // buffer = createHash('sha256').update(buffer).digest()
1420
+ // // const mainHash = buffer
1421
+ // // buffer = createHash('sha256').update(buffer).digest()
1422
+ // // const checksum = buffer.toString('hex').substring(0, 8)
1423
+ // // return base58.encode(Buffer.concat([mainHash, Buffer.from(checksum, 'hex')]))
1424
+ // const payload = Buffer.allocUnsafe(21)
1425
+ // payload.writeUInt8(networks['bitcoin'].pubKeyHash, 0)
1426
+ // buffer.copy(payload, 1)
1427
+ //
1428
+ // return encode(payload)
1429
+ // }
1675
1430
 
1676
- return address.value
1677
- };
1431
+ get leofcoinAddress() {
1432
+ return encode$1(this.neutered.publicKeyBuffer)
1433
+ }
1678
1434
 
1679
- const degreesToRadians = (degrees) => {
1680
- return degrees * Math.PI / 180;
1681
- };
1435
+ get address() {
1436
+ return this.getAddressForCoin()
1437
+ }
1682
1438
 
1683
- const distanceInKmBetweenEarthCoordinates = (lat1, lon1, lat2, lon2) => {
1684
- const earthRadiusKm = 6371;
1439
+ getAddressForCoin(coin_type) {
1440
+ if (!coin_type) coin_type = this.hdnode.network.coin_type;
1441
+ if (coin_type === 1) {
1442
+ if (this.networkName?.split(':')[0] === 'ethereum') coin_type = 60;
1443
+ if (this.networkName?.split(':')[0] === 'leofcoin') coin_type = 640;
1444
+ }
1445
+ // if (coin_type === 0) return this.bitcoinAddress
1446
+ if (coin_type === 60) return this.ethereumAddress
1447
+ if (coin_type === 640) return this.leofcoinAddress
1448
+ }
1685
1449
 
1686
- const dLat = degreesToRadians(lat2-lat1);
1687
- const dLon = degreesToRadians(lon2-lon1);
1450
+ get accountAddress() {
1451
+ return this.ifNotLocked(() => encode$1(this.hdnode.publicKeyBuffer))
1452
+ }
1688
1453
 
1689
- lat1 = degreesToRadians(lat1);
1690
- lat2 = degreesToRadians(lat2);
1691
- const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
1692
- Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
1693
- const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
1694
- return earthRadiusKm * c;
1695
- };
1454
+ get isTestnet() {
1455
+ if (typeof network === 'string')
1456
+ this.hdnode.network = fromNetworkString(network);
1696
1457
 
1697
- class DhtEarth {
1698
- /**
1699
- *
1700
- */
1701
- constructor() {
1702
- this.providerMap = new Map();
1703
- }
1458
+ return Boolean(this.hdnode.network.coin_type === 1)
1459
+ }
1704
1460
 
1705
- /**
1706
- * @param {Object} address
1707
- * @return {Object} {latitude: lat, longitude: lon}
1708
- */
1709
- async getCoordinates(address) {
1710
- // const {address} = parseAddress(provider)
1711
- const request = `https://whereis.leofcoin.org/?ip=${address}`;
1712
- let response = await fetch(request);
1713
- response = await response.json();
1714
- const {lat, lon} = response;
1715
- return {latitude: lat, longitude: lon}
1716
- }
1461
+ constructor(network, hdnode) {
1462
+ if (typeof network === 'string') {
1463
+ this.networkName = network;
1464
+ this.network = fromNetworkString(network);
1465
+ } else if (typeof network === 'object')
1466
+ this.network = network;
1717
1467
 
1718
- /**
1719
- * @param {Object} peer
1720
- * @param {Object} provider
1721
- * @return {Object} {provider, distance}
1722
- */
1723
- async getDistance(peer, provider) {
1724
- const {latitude, longitude} = await this.getCoordinates(provider.address);
1725
- return {provider, distance: distanceInKmBetweenEarthCoordinates(peer.latitude, peer.longitude, latitude, longitude)}
1726
- }
1468
+ if (hdnode) this.defineHDNode(hdnode);
1469
+ }
1727
1470
 
1728
- /**
1729
- * @param {Array} providers
1730
- * @return {Object} closestPeer
1731
- */
1732
- async closestPeer(providers) {
1733
- let all = [];
1734
- const address = await getAddress();
1735
- const peerLoc = await this.getCoordinates(address);
1471
+ ifNotLocked(fn, params) {
1472
+ if (!this.locked) return fn(params);
1473
+ return null
1474
+ }
1736
1475
 
1737
- for (const provider of providers) {
1738
- if (provider.address === '127.0.0.1') all.push({provider, distance: 0});
1739
- else all.push(this.getDistance(peerLoc, provider));
1740
- }
1476
+ defineHDNode(value) {
1477
+ Object.defineProperty(this, 'hdnode', {
1478
+ configurable: false,
1479
+ writable: false,
1480
+ value: value
1481
+ });
1482
+ }
1741
1483
 
1742
- all = await Promise.all(all);
1743
- all = all.sort((previous, current) => previous.distance - current.distance);
1744
- return all[0].provider;
1745
- }
1484
+ validateNetwork(network) {
1485
+ if (!network && !this.network) return console.error(`expected network to be defined`);
1486
+ if (!network && this.network) network = this.network;
1487
+ if (typeof network === 'string') network = fromNetworkString(network);
1488
+ if (typeof network !== 'object') return console.error('network not found');
1489
+ return network;
1490
+ }
1746
1491
 
1747
- /**
1748
- * @param {String} hash
1749
- * @return {Array} providers
1750
- */
1751
- providersFor(hash) {
1752
- return this.providerMap.get(hash);
1753
- }
1492
+ async generate(password, network) {
1493
+ network = this.validateNetwork(network);
1494
+ const mnemonic = new Mnemonic__default["default"]().generate();
1495
+ const seed = new Mnemonic__default["default"]().seedFromMnemonic(mnemonic, password);
1496
+ this.defineHDNode(bip32__namespace.fromSeed(seed, network));
1497
+ return mnemonic;
1498
+ }
1754
1499
 
1755
- /**
1756
- * @param {String} address
1757
- * @param {String} hash
1758
- * @return {Array} providers
1500
+ /**
1501
+ * recover using mnemonic (recovery word list)
1759
1502
  */
1760
- async addProvider(address, hash) {
1761
- let providers = [];
1762
- if (this.providerMap.has(hash)) providers = this.providerMap.get(hash);
1763
-
1764
- providers = new Set([...providers, address]);
1765
- this.providerMap.set(hash, providers);
1766
- return providers;
1767
- }
1768
- }
1769
-
1770
- /**
1771
- * @params {String} network
1772
- * @return {object} { identity, accounts, config }
1773
- */
1774
- var generateAccount = async network => {
1775
- let wallet = new MultiWallet__default["default"](network);
1776
- /**
1777
- * @type {string}
1778
- */
1779
- const mnemonic = await wallet.generate();
1503
+ async recover(mnemonic, password, network) {
1504
+ network = this.validateNetwork(network, password);
1505
+ const seed = new Mnemonic__default["default"]().seedFromMnemonic(mnemonic, password);
1506
+ this.defineHDNode(bip32__namespace.fromSeed(seed, network));
1507
+ }
1780
1508
 
1781
- wallet = new MultiWallet__default["default"](network);
1782
- await wallet.recover(mnemonic, network);
1783
- /**
1784
- * @type {object}
1785
- */
1786
- const account = wallet.account(0);
1787
- /**
1788
- * @type {object}
1789
- */
1790
- const external = account.external(0);
1791
- const internal = account.internal(0);
1509
+ load(base58, network) {
1510
+ network = this.validateNetwork(network);
1511
+ this.defineHDNode(bip32__namespace.fromBase58(base58, network));
1512
+ }
1792
1513
 
1793
- return {
1794
- identity: {
1795
- mnemonic,
1796
- // multiWIF: wallet.export(),
1797
- publicKey: external.publicKey,
1798
- privateKey: external.privateKey,
1799
- walletId: external.id
1800
- },
1801
- accounts: [['main account', external.address, internal.address]]
1802
- // config: {
1803
- // }
1804
- }
1805
- };
1806
-
1807
- var testnets = {
1808
- 'leofcoin:olivia': {
1809
- messagePrefix: '\u0019Leofcoin Signed Message:',
1810
- pubKeyHash: 0x73, // o
1811
- scriptHash: 0x76, // p
1812
- multiTxHash: 0x8b4125, // omtx
1813
- payments: {
1814
- version: 0,
1815
- unspent: 0x1fa443d7 // ounsp
1816
- },
1817
- wif: 0x7D, // s
1818
- multiCodec: 0x7c4,
1819
- bip32: { public: 0x13BBF2D5, private: 0x13BBCBC5 }
1820
- },
1821
- 'bitcoin:testnet': {
1822
- messagePrefix: '\x18Bitcoin Signed Message:\n',
1823
- bech32: 'tb',
1824
- pubKeyHash: 0x6f,
1825
- scriptHash: 0xc4,
1826
- wif: 0xef,
1827
- bip32: {
1828
- public: 0x043587cf,
1829
- private: 0x04358394
1830
- }
1831
- }
1514
+ save() {
1515
+ return this.hdnode.toBase58();
1516
+ }
1832
1517
 
1833
- };
1518
+ fromAddress(address, chainCode, network) {
1519
+ network = this.validateNetwork(network);
1520
+ // if (network.coin_type === 60) {
1521
+ // address = Buffer.from(address, 'hex')
1522
+ // } else {
1523
+ address = decode$1(address);
1524
+ // }
1525
+
1526
+ if (!chainCode || chainCode && !Buffer.isBuffer(chainCode)) chainCode = address.slice(1);
1527
+ this.defineHDNode(bip32__namespace.fromPublicKey(address, chainCode, network));
1528
+ }
1529
+
1530
+ fromPublicKey(hex, chainCode, network) {
1531
+ network = this.validateNetwork(network);
1532
+ if (!Buffer.isBuffer(hex)) hex = Buffer.from(hex, 'hex');
1533
+ if (!chainCode || chainCode && !Buffer.isBuffer(chainCode)) chainCode = hex.slice(1);
1534
+ this.defineHDNode(bip32__namespace.fromPublicKey(hex, chainCode, network));
1535
+ }
1536
+ }
1834
1537
 
1835
- // https://en.bitcoin.it/wiki/List_of_address_prefixes
1836
- /**
1837
- * Main network
1838
- * @return {messagePrefix, pubKeyHash, scriptHash, wif, bip32}
1839
- */
1840
- const leofcoin = {
1841
- messagePrefix: '\u0019Leofcoin Signed Message:',
1842
- pubKeyHash: 0x30, // L
1843
- scriptHash: 0x37, // P
1844
- multiTxHash: 0x3adeed, // Lmtx
1845
- payments: {
1846
- version: 0,
1847
- unspent: 0x0d6e0327 // Lunsp
1848
- },
1849
- coin_type: 640,
1850
- wif: 0x3F, // S
1851
- multiCodec: 0x3c4,
1852
- bip32: { public: 0x13BBF2D4, private: 0x13BBCBC4 },
1853
- testnet: testnets['leofcoin:olivia']
1854
- };
1538
+ const { subtle } = crypto;
1855
1539
 
1856
- const bitcoin = {
1857
- messagePrefix: '\x18Bitcoin Signed Message:\n',
1858
- bech32: 'bc',
1859
- pubKeyHash: 0x00,
1860
- multiCodec: 0x00,
1861
- scriptHash: 0x05,
1862
- wif: 0x80,
1863
- coin_type: 0,
1864
- bip32: {
1865
- public: 0x0488b21e, private: 0x0488ade4
1866
- },
1867
- testnet: testnets['bitcoin:testnet']
1540
+ const generateAesKey = async (length = 256) => {
1541
+ const key = await subtle.generateKey({
1542
+ name: 'AES-CBC',
1543
+ length
1544
+ }, true, ['encrypt', 'decrypt']);
1545
+
1546
+ return key;
1868
1547
  };
1869
1548
 
1870
- const litecoin = {
1871
- messagePrefix: '\x19Litecoin Signed Message:\n',
1872
- pubKeyHash: 0x30,
1873
- scriptHash: 0x32,
1874
- wif: 0xb0,
1875
- bip32: {
1876
- public: 0x019da462,
1877
- private: 0x019d9cfe
1878
- }
1549
+ const importAesKey = async (exported, format = 'raw', length = 256) => {
1550
+ return await subtle.importKey(format, exported, {
1551
+ name: 'AES-CBC',
1552
+ length
1553
+ }, true, ['encrypt', 'decrypt'])
1879
1554
  };
1880
1555
 
1881
- const ethereum = {
1882
- messagePrefix: '\x19Ethereum Signed Message:\n',
1883
- pubKeyHash: 0x30,
1884
- scriptHash: 0x32,
1885
- bip32: {
1886
- private: 0x0488ADE4, public: 0x0488B21E
1887
- },
1888
- coin_type: 60,
1889
- wif: 0x45,//E
1890
- multiCodec: 0x3c5
1556
+ const exportAesKey = async (key, format = 'raw') => {
1557
+ return await subtle.exportKey(format, key)
1891
1558
  };
1892
1559
 
1893
- /**
1894
- * Our & supported networks
1895
- * @return {leofcoin, olivia}
1896
- */
1897
- var networks = {
1898
- leofcoin,
1899
- bitcoin,
1900
- litecoin,
1901
- ethereum
1902
- };
1903
-
1904
- const fromNetworkString = network => {
1905
- const parts = network.split(':');
1906
- network = networks[parts[0]];
1907
- if (parts[1]) {
1908
- if (network[parts[1]]) network = network[parts[1]];
1560
+ const encryptAes = async (uint8Array, key, iv) => subtle.encrypt({
1561
+ name: 'AES-CBC',
1562
+ iv,
1563
+ }, key, uint8Array);
1909
1564
 
1910
- network.coin_type = 1;
1565
+ const uint8ArrayToHex = uint8Array =>
1566
+ [...uint8Array].map(x => x.toString(16).padStart(2, '0')).join('');
1567
+
1568
+ const arrayBufferToHex = arrayBuffer =>
1569
+ uint8ArrayToHex(new Uint8Array(arrayBuffer));
1570
+
1571
+ const hexToUint8Array = hex =>
1572
+ new Uint8Array(hex.match(/[\da-f]{2}/gi).map(x => parseInt(x, 16)));
1573
+
1574
+ const encrypt = async string => {
1575
+ const ec = new TextEncoder();
1576
+ const key = await generateAesKey();
1577
+ const iv = await randombytes__default["default"](16);
1578
+
1579
+ const ciphertext = await encryptAes(ec.encode(string), key, iv);
1580
+ const exported = await exportAesKey(key);
1581
+
1582
+ return {
1583
+ key: arrayBufferToHex(exported),
1584
+ iv: iv.toString('hex'),
1585
+ cipher: arrayBufferToHex(ciphertext)
1911
1586
  }
1912
- return network;
1587
+ };
1588
+
1589
+ const decrypt = async (cipher, key, iv) => {
1590
+ if (!key.type) key = await importAesKey(hexToUint8Array(key));
1591
+ cipher = new Uint8Array(hexToUint8Array(cipher));
1592
+ iv = new Uint8Array(hexToUint8Array(iv));
1593
+
1594
+ const dec = new TextDecoder();
1595
+ const plaintext = await subtle.decrypt({
1596
+ name: 'AES-CBC',
1597
+ iv,
1598
+ }, key, cipher);
1599
+
1600
+ return dec.decode(plaintext);
1913
1601
  };
1914
1602
 
1915
- // import { createHash } from 'crypto'
1916
- // import { createHash as _createHash } from './hash'
1603
+ const { encode, decode } = bs58check__namespace;
1917
1604
 
1918
- const { encode: encode$1, decode: decode$1 } = bs58check__default["default"];
1919
- class HDWallet {
1605
+ // TODO: multihash addresses
1606
+ class HDAccount {
1607
+ /**
1608
+ * @param {number} depth - acount depth
1609
+ */
1610
+ constructor(node, depth = 0) {
1611
+ this.node = node;
1612
+ this.depth = depth;
1613
+ this._prefix = `m/44'/${node.network.coin_type}'/${depth}'/`;
1614
+ }
1920
1615
 
1921
- get chainCodeBuffer() {
1922
- return this.ifNotLocked(() => this.hdnode.chainCode)
1616
+ /**
1617
+ * @param {number} index - address index
1618
+ */
1619
+ internal(index = 0) {
1620
+ return this.node.derivePath(`${this._prefix}1/${index}`)
1923
1621
  }
1924
1622
 
1925
- get chainCode() {
1926
- return this.ifNotLocked(() => this.chainCodeBuffer.toString('hex'))
1623
+ /**
1624
+ * @param {number} index - address index
1625
+ */
1626
+ external(index = 0) {
1627
+ return this.node.derivePath(`${this._prefix}0/${index}`)
1927
1628
  }
1629
+ }
1928
1630
 
1929
- get privateKeyBuffer() {
1930
- return this.ifNotLocked(() => this.hdnode.privateKey)
1631
+ class MultiWallet extends HDWallet {
1632
+ constructor(network, hdnode) {
1633
+ super(network, hdnode);
1634
+ this.multiCodec = this.network.multiCodec;
1635
+ this.version = 0x00;
1931
1636
  }
1932
1637
 
1933
- get privateKey() {
1934
- return this.ifNotLocked(() => this.privateKeyBuffer.toString('hex'))
1638
+ get id() {
1639
+ const buffer = Buffer.concat([
1640
+ Buffer.from(varint__default["default"].encode(this.multiCodec)),
1641
+ Buffer.from(this.account(0).node.neutered.publicKey, 'hex')
1642
+ ]);
1643
+ return encode(buffer)
1935
1644
  }
1936
1645
 
1937
- get publicKeyBuffer() {
1938
- return this.ifNotLocked(() => this.hdnode.publicKey)
1646
+ get multiWIF() {
1647
+ return this.ifNotLocked(() => this.encode())
1939
1648
  }
1940
1649
 
1941
- get publicKey() {
1942
- return this.ifNotLocked(() => this.publicKeyBuffer.toString('hex'))
1943
- }
1944
-
1945
- get ethereumAddress() {
1946
- const buffer = ecc__default["default"].pointFromScalar(this.hdnode.__D, false);
1947
- let hash = createKeccakHash__default["default"]('keccak256').update(buffer.slice(1)).digest();
1948
- return `0x${hash.slice(-20).toString('hex')}`
1949
- }
1950
-
1951
- // async bitcoinAddress() {
1952
- // const chainCode = this.privateKeyBuffer
1953
- //
1954
- // const node = bip32.fromPrivateKey(this.privateKeyBuffer, chainCode, networks['bitcoin'])
1955
- // let buffer = await _createHash(node.publicKey, 'SHA-256')
1956
- // buffer = createHash('ripemd160').update(buffer).digest()
1957
- // // buffer = Buffer.from(`0x00${buffer.toString('hex')}`, 'hex')
1958
- // // buffer = createHash('sha256').update(buffer).digest()
1959
- // // const mainHash = buffer
1960
- // // buffer = createHash('sha256').update(buffer).digest()
1961
- // // const checksum = buffer.toString('hex').substring(0, 8)
1962
- // // return base58.encode(Buffer.concat([mainHash, Buffer.from(checksum, 'hex')]))
1963
- // const payload = Buffer.allocUnsafe(21)
1964
- // payload.writeUInt8(networks['bitcoin'].pubKeyHash, 0)
1965
- // buffer.copy(payload, 1)
1966
- //
1967
- // return encode(payload)
1968
- // }
1969
-
1970
- get leofcoinAddress() {
1971
- return encode$1(this.neutered.publicKeyBuffer)
1972
- }
1973
-
1974
- get address() {
1975
- return this.getAddressForCoin()
1976
- }
1977
-
1978
- getAddressForCoin(coin_type) {
1979
- if (!coin_type) coin_type = this.hdnode.network.coin_type;
1980
- if (coin_type === 1) {
1981
- if (this.networkName?.split(':')[0] === 'ethereum') coin_type = 60;
1982
- if (this.networkName?.split(':')[0] === 'leofcoin') coin_type = 640;
1983
- }
1984
- // if (coin_type === 0) return this.bitcoinAddress
1985
- if (coin_type === 60) return this.ethereumAddress
1986
- if (coin_type === 640) return this.leofcoinAddress
1987
- }
1988
-
1989
- get accountAddress() {
1990
- return this.ifNotLocked(() => encode$1(this.hdnode.publicKeyBuffer))
1991
- }
1992
-
1993
- get isTestnet() {
1994
- if (typeof network === 'string')
1995
- this.hdnode.network = fromNetworkString(network);
1996
-
1997
- return Boolean(this.hdnode.network.coin_type === 1)
1998
- }
1999
-
2000
- constructor(network, hdnode) {
2001
- if (typeof network === 'string') {
2002
- this.networkName = network;
2003
- this.network = fromNetworkString(network);
2004
- } else if (typeof network === 'object')
2005
- this.network = network;
2006
-
2007
- if (hdnode) this.defineHDNode(hdnode);
2008
- }
2009
-
2010
- ifNotLocked(fn, params) {
2011
- if (!this.locked) return fn(params);
2012
- return null
2013
- }
2014
-
2015
- defineHDNode(value) {
2016
- Object.defineProperty(this, 'hdnode', {
2017
- configurable: false,
2018
- writable: false,
2019
- value: value
2020
- });
2021
- }
2022
-
2023
- validateNetwork(network) {
2024
- if (!network && !this.network) return console.error(`expected network to be defined`);
2025
- if (!network && this.network) network = this.network;
2026
- if (typeof network === 'string') network = fromNetworkString(network);
2027
- if (typeof network !== 'object') return console.error('network not found');
2028
- return network;
2029
- }
2030
-
2031
- async generate(password, network) {
2032
- network = this.validateNetwork(network);
2033
- const mnemonic = new Mnemonic__default["default"]().generate();
2034
- const seed = new Mnemonic__default["default"]().seedFromMnemonic(mnemonic, password);
2035
- this.defineHDNode(bip32__namespace.fromSeed(seed, network));
2036
- return mnemonic;
2037
- }
2038
-
2039
- /**
2040
- * recover using mnemonic (recovery word list)
2041
- */
2042
- async recover(mnemonic, password, network) {
2043
- network = this.validateNetwork(network, password);
2044
- const seed = new Mnemonic__default["default"]().seedFromMnemonic(mnemonic, password);
2045
- this.defineHDNode(bip32__namespace.fromSeed(seed, network));
2046
- }
2047
-
2048
- load(base58, network) {
2049
- network = this.validateNetwork(network);
2050
- this.defineHDNode(bip32__namespace.fromBase58(base58, network));
2051
- }
2052
-
2053
- save() {
2054
- return this.hdnode.toBase58();
2055
- }
2056
-
2057
- fromAddress(address, chainCode, network) {
2058
- network = this.validateNetwork(network);
2059
- // if (network.coin_type === 60) {
2060
- // address = Buffer.from(address, 'hex')
2061
- // } else {
2062
- address = decode$1(address);
2063
- // }
2064
-
2065
- if (!chainCode || chainCode && !Buffer.isBuffer(chainCode)) chainCode = address.slice(1);
2066
- this.defineHDNode(bip32__namespace.fromPublicKey(address, chainCode, network));
2067
- }
2068
-
2069
- fromPublicKey(hex, chainCode, network) {
2070
- network = this.validateNetwork(network);
2071
- if (!Buffer.isBuffer(hex)) hex = Buffer.from(hex, 'hex');
2072
- if (!chainCode || chainCode && !Buffer.isBuffer(chainCode)) chainCode = hex.slice(1);
2073
- this.defineHDNode(bip32__namespace.fromPublicKey(hex, chainCode, network));
2074
- }
2075
- }
2076
-
2077
- const { subtle } = crypto;
2078
-
2079
- const generateAesKey = async (length = 256) => {
2080
- const key = await subtle.generateKey({
2081
- name: 'AES-CBC',
2082
- length
2083
- }, true, ['encrypt', 'decrypt']);
2084
-
2085
- return key;
2086
- };
2087
-
2088
- const importAesKey = async (exported, format = 'raw', length = 256) => {
2089
- return await subtle.importKey(format, exported, {
2090
- name: 'AES-CBC',
2091
- length
2092
- }, true, ['encrypt', 'decrypt'])
2093
- };
2094
-
2095
- const exportAesKey = async (key, format = 'raw') => {
2096
- return await subtle.exportKey(format, key)
2097
- };
2098
-
2099
- const encryptAes = async (uint8Array, key, iv) => subtle.encrypt({
2100
- name: 'AES-CBC',
2101
- iv,
2102
- }, key, uint8Array);
2103
-
2104
- const uint8ArrayToHex = uint8Array =>
2105
- [...uint8Array].map(x => x.toString(16).padStart(2, '0')).join('');
2106
-
2107
- const arrayBufferToHex = arrayBuffer =>
2108
- uint8ArrayToHex(new Uint8Array(arrayBuffer));
2109
-
2110
- const hexToUint8Array = hex =>
2111
- new Uint8Array(hex.match(/[\da-f]{2}/gi).map(x => parseInt(x, 16)));
2112
-
2113
- const encrypt = async string => {
2114
- const ec = new TextEncoder();
2115
- const key = await generateAesKey();
2116
- const iv = await randombytes__default["default"](16);
2117
-
2118
- const ciphertext = await encryptAes(ec.encode(string), key, iv);
2119
- const exported = await exportAesKey(key);
2120
-
2121
- return {
2122
- key: arrayBufferToHex(exported),
2123
- iv: iv.toString('hex'),
2124
- cipher: arrayBufferToHex(ciphertext)
2125
- }
2126
- };
2127
-
2128
- const decrypt = async (cipher, key, iv) => {
2129
- if (!key.type) key = await importAesKey(hexToUint8Array(key));
2130
- cipher = new Uint8Array(hexToUint8Array(cipher));
2131
- iv = new Uint8Array(hexToUint8Array(iv));
2132
-
2133
- const dec = new TextDecoder();
2134
- const plaintext = await subtle.decrypt({
2135
- name: 'AES-CBC',
2136
- iv,
2137
- }, key, cipher);
2138
-
2139
- return dec.decode(plaintext);
2140
- };
2141
-
2142
- const { encode, decode } = bs58check__namespace;
2143
-
2144
- // TODO: multihash addresses
2145
- class HDAccount {
2146
- /**
2147
- * @param {number} depth - acount depth
2148
- */
2149
- constructor(node, depth = 0) {
2150
- this.node = node;
2151
- this.depth = depth;
2152
- this._prefix = `m/44'/${node.network.coin_type}'/${depth}'/`;
2153
- }
2154
-
2155
- /**
2156
- * @param {number} index - address index
2157
- */
2158
- internal(index = 0) {
2159
- return this.node.derivePath(`${this._prefix}1/${index}`)
2160
- }
2161
-
2162
- /**
2163
- * @param {number} index - address index
2164
- */
2165
- external(index = 0) {
2166
- return this.node.derivePath(`${this._prefix}0/${index}`)
2167
- }
2168
- }
2169
-
2170
- class MultiWallet extends HDWallet {
2171
- constructor(network, hdnode) {
2172
- super(network, hdnode);
2173
- this.multiCodec = this.network.multiCodec;
2174
- this.version = 0x00;
2175
- }
2176
-
2177
- get id() {
2178
- const buffer = Buffer.concat([
2179
- Buffer.from(varint__default["default"].encode(this.multiCodec)),
2180
- Buffer.from(this.account(0).node.neutered.publicKey, 'hex')
2181
- ]);
2182
- return encode(buffer)
2183
- }
2184
-
2185
- get multiWIF() {
2186
- return this.ifNotLocked(() => this.encode())
2187
- }
2188
-
2189
- get neutered() {
2190
- const neutered = this.ifNotLocked(() => new MultiWallet(this.networkName, this.hdnode.neutered()));
2191
- if (neutered) this._neutered = neutered;
2192
- return this._neutered
1650
+ get neutered() {
1651
+ const neutered = this.ifNotLocked(() => new MultiWallet(this.networkName, this.hdnode.neutered()));
1652
+ if (neutered) this._neutered = neutered;
1653
+ return this._neutered
2193
1654
  }
2194
1655
 
2195
1656
  fromId(id) {
@@ -2243,707 +1704,1272 @@ class MultiWallet extends HDWallet {
2243
1704
  return encode(buffer);
2244
1705
  }
2245
1706
 
2246
- decode(bs58) {
2247
- let buffer = decode(bs58);
2248
- const version = varint__default["default"].decode(buffer);
2249
- buffer = buffer.slice(varint__default["default"].decode.bytes);
2250
- const multiCodec = varint__default["default"].decode(buffer);
2251
- buffer = buffer.slice(varint__default["default"].decode.bytes);
2252
- bs58 = encode(buffer);
2253
- if (version !== this.version) throw TypeError('Invalid version');
2254
- if (this.multiCodec !== multiCodec) throw TypeError('Invalid multiCodec');
2255
- return { version, multiCodec, bs58 };
2256
- }
1707
+ decode(bs58) {
1708
+ let buffer = decode(bs58);
1709
+ const version = varint__default["default"].decode(buffer);
1710
+ buffer = buffer.slice(varint__default["default"].decode.bytes);
1711
+ const multiCodec = varint__default["default"].decode(buffer);
1712
+ buffer = buffer.slice(varint__default["default"].decode.bytes);
1713
+ bs58 = encode(buffer);
1714
+ if (version !== this.version) throw TypeError('Invalid version');
1715
+ if (this.multiCodec !== multiCodec) throw TypeError('Invalid multiCodec');
1716
+ return { version, multiCodec, bs58 };
1717
+ }
1718
+
1719
+ sign(hash) {
1720
+ return new MultiSignature__default["default"](this.version, this.network.multiCodec)
1721
+ .sign(hash, this.privateKeyBuffer);
1722
+
1723
+ }
1724
+
1725
+ verify(multiSignature, hash) {
1726
+ return new MultiSignature__default["default"](this.version, this.network.multiCodec)
1727
+ .verify(multiSignature, hash, this.publicKeyBuffer)
1728
+ }
1729
+
1730
+ /**
1731
+ * @param {number} account - account to return chain for
1732
+ * @return { internal(addressIndex), external(addressIndex) }
1733
+ */
1734
+ account(index) {
1735
+ return new HDAccount(new MultiWallet(this.networkName, this.hdnode), index);
1736
+ }
1737
+
1738
+ /**
1739
+ * m / purpose' / coin_type' / account' / change / aadress_index
1740
+ *
1741
+ * see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
1742
+ */
1743
+ derivePath(path) {
1744
+ return new MultiWallet(this.networkName, this.hdnode.derivePath(path))
1745
+ }
1746
+
1747
+ derive(index) {
1748
+ return new MultiWallet(this.networkName, this.hdnode.derive(index));
1749
+ }
1750
+ }
1751
+
1752
+ class MessageHandler {
1753
+ constructor(network) {
1754
+ this.network = network;
1755
+ }
1756
+ /**
1757
+ * hash and sign message
1758
+ *
1759
+ * @param {object} message
1760
+ * @param {Buffer} message.from peer id
1761
+ * @param {Buffer} message.to peer id
1762
+ * @param {string} message.data Peernet message
1763
+ * (PeernetMessage excluded) encoded as a string
1764
+ * @return signature
1765
+ */
1766
+ async hashAndSignMessage(message) {
1767
+ const hasher = new codecFormatInterface.CodecHash(message, {name: 'peernet-message'});
1768
+ let identity = await walletStore.get('identity');
1769
+ identity = JSON.parse(new TextDecoder().decode(identity));
1770
+ const wallet = new MultiWallet(this.network);
1771
+ wallet.recover(identity.mnemonic);
1772
+ return wallet.sign(Buffer.from(hasher.hash).slice(0, 32))
1773
+ }
1774
+
1775
+ /**
1776
+ * @param {String} from - peer id
1777
+ * @param {String} to - peer id
1778
+ * @param {String|PeernetMessage} data - data encoded message string
1779
+ * or the messageNode itself
1780
+ */
1781
+ async prepareMessage(from, to, data, id) {
1782
+ if (data.encoded) data = data.encoded;
1783
+
1784
+ const message = {
1785
+ from,
1786
+ to,
1787
+ data,
1788
+ };
1789
+ const signature = await this.hashAndSignMessage(message);
1790
+ const node = new PeernetMessage({
1791
+ ...message,
1792
+ signature,
1793
+ });
1794
+
1795
+ return node
1796
+ }
1797
+ }
1798
+
1799
+ const dataHandler = async message => {
1800
+ if (!message) return
1801
+
1802
+ const {data, id} = message;
1803
+
1804
+ message = protoFor(data);
1805
+ const proto = protoFor(message.decoded.data);
1806
+ const from = message.decoded.from;
1807
+
1808
+ peernet._protoHandler({id, proto}, peernet.client.connections[from], from);
1809
+ };
1810
+
1811
+ const encapsulatedError = () => {
1812
+ return new Error('Nodes/Data should be send encapsulated by peernet-message')
1813
+ };
1814
+
1815
+ const dhtError = (proto) => {
1816
+ const text = `Received proto ${proto.name} expected peernet-dht-response`;
1817
+ return new Error(`Routing error: ${text}`)
1818
+ };
1819
+
1820
+ const nothingFoundError = (hash) => {
1821
+ return new Error(`nothing found for ${hash}`)
1822
+ };
1823
+
1824
+ globalThis.leofcoin = globalThis.leofcoin || {};
1825
+ globalThis.globalSub = globalThis.globalSub || new PubSub({verbose: true});
1826
+
1827
+ /**
1828
+ * @access public
1829
+ * @example
1830
+ * const peernet = new Peernet();
1831
+ */
1832
+ class Peernet {
1833
+ /**
1834
+ * @access public
1835
+ * @param {Object} options
1836
+ * @param {String} options.network - desired network
1837
+ * @param {String} options.root - path to root directory
1838
+ * @param {String} options.storePrefix - prefix for datatores (lfc)
1839
+ *
1840
+ * @return {Promise} instance of Peernet
1841
+ *
1842
+ * @example
1843
+ * const peernet = new Peernet({network: 'leofcoin', root: '.leofcoin'});
1844
+ */
1845
+ constructor(options = {}) {
1846
+ this._discovered = [];
1847
+ /**
1848
+ * @property {String} network - current network
1849
+ */
1850
+ this.network = options.network || 'leofcoin';
1851
+ const parts = this.network.split(':');
1852
+
1853
+ if (!options.storePrefix) options.storePrefix = 'lfc';
1854
+ if (!options.port) options.port = 2000;
1855
+ if (!options.root) {
1856
+ if (parts[1]) options.root = `.${parts[0]}/peernet/${parts[1]}`;
1857
+ else options.root = `.${this.network}/peernet`;
1858
+ }
1859
+ globalThis.peernet = this;
1860
+ this.bw = {
1861
+ up: 0,
1862
+ down: 0,
1863
+ };
1864
+ return this._init(options)
1865
+ }
1866
+
1867
+ get defaultStores() {
1868
+ return ['account', 'wallet', 'block', 'transaction', 'chain', 'data', 'message']
1869
+ }
1870
+
1871
+ addProto(name, proto) {
1872
+ if (!this.protos[name]) this.protos[name] = proto;
1873
+ }
1874
+
1875
+ addCodec(name, codec) {
1876
+ if (!this.codecs[name]) this.codecs[name] = codec;
1877
+ }
1878
+
1879
+ async addStore(name, prefix, root, isPrivate = true) {
1880
+ if (name === 'block' || name === 'transaction' || name === 'chain' ||
1881
+ name === 'data' || name === 'message') isPrivate = false;
1882
+
1883
+ let Storage;
1884
+ if (this.hasDaemon) {
1885
+ Storage = LeofcoinStorageClient;
1886
+ } else {
1887
+ Storage = globalThis.LeofcoinStorage?.default ? globalThis.LeofcoinStorage.default : LeofcoinStorage__default["default"];
1888
+ }
1889
+ globalThis[`${name}Store`] = globalThis[`${name}Store`] ||
1890
+ await new Storage(name, root);
1891
+
1892
+ globalThis[`${name}Store`].private = isPrivate;
1893
+ if (!isPrivate) this.stores.push(name);
1894
+ }
1895
+
1896
+
1897
+ /**
1898
+ * @see MessageHandler
1899
+ */
1900
+ prepareMessage(to, data) {
1901
+ return this._messageHandler.prepareMessage(this.id, to, data)
1902
+ }
1903
+
1904
+ /**
1905
+ * @access public
1906
+ *
1907
+ * @return {Array} peerId
1908
+ */
1909
+ get peers() {
1910
+ return Object.keys(this.client.connections)
1911
+ }
1912
+
1913
+ get connections() {
1914
+ return Object.values(this.client.connections)
1915
+ }
1916
+
1917
+ get peerEntries() {
1918
+ return Object.entries(this.client.connections)
1919
+ }
1920
+
1921
+ /**
1922
+ * @return {String} id - peerId
1923
+ */
1924
+ getConnection(id) {
1925
+ return this.client.connections[id]
1926
+ }
1927
+
1928
+ /**
1929
+ * @private
1930
+ *
1931
+ * @param {Object} options
1932
+ * @param {String} options.root - path to root directory
1933
+ *
1934
+ * @return {Promise} instance of Peernet
1935
+ */
1936
+ async _init(options) {
1937
+ // peernetDHT aka closesPeer by coordinates
1938
+ /**
1939
+ * @type {Object}
1940
+ * @property {Object} peer Instance of Peer
1941
+ */
1942
+ this.dht = new DhtEarth();
1943
+ /**
1944
+ * @type {Map}
1945
+ * @property {Object} peer Instance of Peer
1946
+ */
1947
+ this.stores = [];
1948
+ this.requestProtos = {};
1949
+ this.storePrefix = options.storePrefix;
1950
+ this.root = options.root;
1951
+
1952
+ /**
1953
+ * proto Object containing protos
1954
+ * @type {Object}
1955
+ * @property {PeernetMessage} protos[peernet-message] messageNode
1956
+ * @property {DHTMessage} protos[peernet-dht] messageNode
1957
+ * @property {DHTMessageResponse} protos[peernet-dht-response] messageNode
1958
+ * @property {DataMessage} protos[peernet-data] messageNode
1959
+ * @property {DataMessageResponse} protos[peernet-data-response] messageNode
1960
+ */
1961
+ globalThis.peernet.protos = {
1962
+ 'peernet-request': RequestMessage,
1963
+ 'peernet-response': ResponseMessage,
1964
+ 'peernet-peer': PeerMessage,
1965
+ 'peernet-peer-response': PeerMessageResponse,
1966
+ 'peernet-message': PeernetMessage,
1967
+ 'peernet-dht': DHTMessage,
1968
+ 'peernet-dht-response': DHTMessageResponse,
1969
+ 'peernet-data': DataMessage,
1970
+ 'peernet-data-response': DataMessageResponse,
1971
+ 'peernet-ps': PsMessage,
1972
+ 'chat-message': ChatMessage,
1973
+ };
1974
+
1975
+ this.protos = globalThis.peernet.protos;
1976
+ this.codecs = codecFormatInterface.codecs;
1977
+
1978
+ this._messageHandler = new MessageHandler(this.network);
1979
+
1980
+ const {daemon, environment} = await target();
1981
+ this.hasDaemon = daemon;
1982
+
1983
+
1984
+
1985
+ for (const store of this.defaultStores) {
1986
+ await this.addStore(store, options.storePrefix, options.root);
1987
+ }
1988
+
1989
+ try {
1990
+ const pub = await accountStore.get('public');
1991
+ this.id = JSON.parse(new TextDecoder().decode(pub)).walletId;
1992
+ } catch (e) {
1993
+ if (e.code === 'ERR_NOT_FOUND') {
1994
+ const {identity, accounts, config} = await generateAccount(this.network);
1995
+ walletStore.put('version', new TextEncoder().encode(1));
1996
+ walletStore.put('accounts', new TextEncoder().encode(accounts));
1997
+ walletStore.put('identity', new TextEncoder().encode(JSON.stringify(identity)));
1998
+ await accountStore.put('config', new TextEncoder().encode(JSON.stringify(config)));
1999
+ await accountStore.put('public', new TextEncoder().encode(JSON.stringify({walletId: identity.walletId})));
2000
+
2001
+ this.id = identity.walletId;
2002
+ } else {
2003
+ throw e
2004
+ }
2005
+ }
2006
+ this._peerHandler = new PeerDiscovery(this.id);
2007
+ this.peerId = this.id;
2008
+
2009
+ pubsub.subscribe('peer:connected', async (peer) => {
2010
+ console.log(peer);
2011
+ // console.log({connected: peer.id, as: this._getPeerId(peer.id) });
2012
+ // peer.on('peernet.data', async (message) => {
2013
+ // const id = message.id
2014
+ // message = new PeernetMessage(Buffer.from(message.data.data))
2015
+ // const proto = protoFor(message.decoded.data)
2016
+ // this._protoHandler({id, proto}, peer)
2017
+ // })
2018
+ });
2019
+
2020
+ /**
2021
+ * converts data -> message -> proto
2022
+ * @see DataHandler
2023
+ */
2024
+ pubsub.subscribe('peer:data', dataHandler);
2025
+
2026
+ /**
2027
+ * @access public
2028
+ * @type {PeernetClient}
2029
+ */
2030
+ this.client = new Client(this.id);
2031
+ if (globalThis.onbeforeunload) {
2032
+ globalThis.addEventListener('beforeunload', async () => this.client.close());
2033
+ }
2034
+ return this
2035
+ }
2036
+
2037
+ addRequestHandler(name, method) {
2038
+ this.requestProtos[name] = method;
2039
+ }
2040
+
2041
+ sendMessage(peer, id, data) {
2042
+ if (peer.readyState === 'open') {
2043
+ peer.send(data, id);
2044
+ this.bw.up += data.length;
2045
+ } else if (peer.readyState === 'closed') ;
2046
+
2047
+ }
2048
+
2049
+ /**
2050
+ * @private
2051
+ *
2052
+ * @param {Buffer} message - peernet message
2053
+ * @param {PeernetPeer} peer - peernet peer
2054
+ */
2055
+ async _protoHandler(message, peer, from) {
2056
+
2057
+ const {id, proto} = message;
2058
+ this.bw.down += proto.encoded.length;
2059
+ if (proto.name === 'peernet-dht') {
2060
+ let { hash, store } = proto.decoded;
2061
+ let has;
2062
+
2063
+ if (!store) {
2064
+ has = await this.has(hash);
2065
+ } else {
2066
+ store = globalThis[`${store}Store`];
2067
+ if (store.private) has = false;
2068
+ else has = await store.has(hash);
2069
+ }
2070
+ const data = new DHTMessageResponse({hash, has});
2071
+ const node = await this.prepareMessage(from, data.encoded);
2072
+
2073
+ this.sendMessage(peer, id, node.encoded);
2074
+ } else if (proto.name === 'peernet-data') {
2075
+ let { hash, store } = proto.decoded;
2076
+ let data;
2077
+ if (!store) {
2078
+ store = await this.whichStore([...this.stores], hash);
2079
+ } else {
2080
+ store = globalThis[`${store}Store`];
2081
+ }
2082
+ if (store && !store.private) {
2083
+ data = await store.get(hash);
2084
+
2085
+ if (data) {
2086
+ data = new DataMessageResponse({hash, data});
2087
+
2088
+ const node = await this.prepareMessage(from, data.encoded);
2089
+ this.sendMessage(peer, id, node.encoded);
2090
+ }
2091
+ }
2092
+
2093
+ } else if (proto.name === 'peernet-request') {
2094
+ const method = this.requestProtos[proto.decoded.request];
2095
+ if (method) {
2096
+ const data = await method();
2097
+ const node = await this.prepareMessage(from, data.encoded);
2098
+ this.sendMessage(peer, id, node.encoded);
2099
+ }
2100
+ } else if (proto.name === 'peernet-ps' && peer.peerId !== this.id) {
2101
+ globalSub.publish(new TextDecoder().decode(proto.decoded.topic), proto.decoded.data);
2102
+ }
2103
+ // }
2104
+ }
2105
+
2106
+ /**
2107
+ * performs a walk and resolves first encounter
2108
+ *
2109
+ * @param {String} hash
2110
+ */
2111
+ async walk(hash) {
2112
+ if (!hash) throw new Error('hash expected, received undefined')
2113
+ const data = new DHTMessage({hash});
2114
+ this.client.id;
2115
+ const walk = async peer => {
2116
+ const node = await this.prepareMessage(peer.peerId, data.encoded);
2117
+ let result = await peer.request(node.encoded);
2118
+ result = new Uint8Array(Object.values(result));
2119
+ let proto = protoFor(result);
2120
+ if (proto.name !== 'peernet-message') throw encapsulatedError()
2121
+ const from = proto.decoded.from;
2122
+ proto = protoFor(proto.decoded.data);
2123
+ if (proto.name !== 'peernet-dht-response') throw dhtError(proto.name)
2124
+
2125
+ // TODO: give ip and port (just used for location)
2126
+ if (!peer.connection.remoteAddress || !peer.connection.localAddress) {
2127
+ peer.connection.remoteFamily = 'ipv4';
2128
+ peer.connection.remoteAddress = '127.0.0.1';
2129
+ peer.connection.remotePort = '0000';
2130
+ }
2131
+
2132
+ const peerInfo = {
2133
+ family: peer.connection.remoteFamily || peer.connection.localFamily,
2134
+ address: peer.connection.remoteAddress || peer.connection.localAddress,
2135
+ port: peer.connection.remotePort || peer.connection.localPort,
2136
+ id: from,
2137
+ };
2138
+
2139
+ if (proto.decoded.has) this.dht.addProvider(peerInfo, proto.decoded.hash);
2140
+ };
2141
+ let walks = [];
2142
+ for (const peer of this.connections) {
2143
+ if (peer.peerId !== this.id) {
2144
+ walks.push(walk(peer));
2145
+ }
2146
+ }
2147
+ return Promise.all(walks)
2148
+ }
2149
+
2150
+ /**
2151
+ * Override DHT behavior, try's finding the content three times
2152
+ *
2153
+ * @param {String} hash
2154
+ */
2155
+ async providersFor(hash) {
2156
+ let providers = await this.dht.providersFor(hash);
2157
+ // walk the network to find a provider
2158
+ if (!providers || providers.length === 0) {
2159
+ await this.walk(hash);
2160
+ providers = await this.dht.providersFor(hash);
2161
+ // second walk the network to find a provider
2162
+ if (!providers || providers.length === 0) {
2163
+ await this.walk(hash);
2164
+ providers = await this.dht.providersFor(hash);
2165
+ }
2166
+ // last walk
2167
+ if (!providers || providers.length === 0) {
2168
+ await this.walk(hash);
2169
+ providers = await this.dht.providersFor(hash);
2170
+ }
2171
+ }
2172
+ // undefined if no providers given
2173
+ return providers
2174
+ }
2175
+
2176
+ get block() {
2177
+ return {
2178
+ get: async (hash) => {
2179
+ const data = await blockStore.has(hash);
2180
+ if (data) return await blockStore.get(hash)
2181
+ return this.requestData(hash, 'block')
2182
+ },
2183
+ put: async (hash, data) => {
2184
+ if (await blockStore.has(hash)) return
2185
+ return await blockStore.put(hash, data)
2186
+ },
2187
+ has: async (hash) => await blockStore.has(hash, 'block'),
2188
+ }
2189
+ }
2190
+
2191
+ get transaction() {
2192
+ return {
2193
+ get: async (hash) => {
2194
+ const data = await transactionStore.has(hash);
2195
+ if (data) return await transactionStore.get(hash)
2196
+ return this.requestData(hash, 'transaction')
2197
+ },
2198
+ put: async (hash, data) => {
2199
+ if (await transactionStore.has(hash)) return
2200
+ return await transactionStore.put(hash, data)
2201
+ },
2202
+ has: async (hash) => await transactionStore.has(hash),
2203
+ }
2204
+ }
2205
+
2206
+ async requestData(hash, store) {
2207
+ const providers = await this.providersFor(hash);
2208
+ if (!providers || providers.size === 0) throw nothingFoundError(hash)
2209
+ debug(`found ${providers.size} provider(s) for ${hash}`);
2210
+ // get closest peer on earth
2211
+ const closestPeer = await this.dht.closestPeer(providers);
2212
+ // get peer instance by id
2213
+ if (!closestPeer || !closestPeer.id) return this.requestData(hash, store?.name ? store?.name : store)
2214
+
2215
+ const id = closestPeer.id;
2216
+ if (this.connections) {
2217
+ let closest = this.connections.filter((peer) => {
2218
+ if (peer.peerId === id) return peer
2219
+ });
2257
2220
 
2258
- sign(hash) {
2259
- return new MultiSignature__default["default"](this.version, this.network.multiCodec)
2260
- .sign(hash, this.privateKeyBuffer);
2221
+ let data = new DataMessage({hash, store: store?.name ? store?.name : store});
2261
2222
 
2262
- }
2223
+ const node = await this.prepareMessage(id, data.encoded);
2224
+ if (closest[0]) data = await closest[0].request(node.encoded);
2225
+ else {
2226
+ closest = this.connections.filter((peer) => {
2227
+ if (peer.peerId === id) return peer
2228
+ });
2229
+ if (closest[0]) data = await closest[0].request(node.encoded);
2230
+ }
2231
+ data = new Uint8Array(Object.values(data));
2232
+ let proto = protoFor(data);
2233
+ proto = protoFor(proto.decoded.data);
2234
+ // TODO: store data automaticly or not
2235
+ return proto.decoded.data
2263
2236
 
2264
- verify(multiSignature, hash) {
2265
- return new MultiSignature__default["default"](this.version, this.network.multiCodec)
2266
- .verify(multiSignature, hash, this.publicKeyBuffer)
2267
- }
2237
+ // this.put(hash, proto.decoded.data)
2238
+ }
2239
+ return null
2240
+ }
2268
2241
 
2269
- /**
2270
- * @param {number} account - account to return chain for
2271
- * @return { internal(addressIndex), external(addressIndex) }
2272
- */
2273
- account(index) {
2274
- return new HDAccount(new MultiWallet(this.networkName, this.hdnode), index);
2275
- }
2276
2242
 
2277
- /**
2278
- * m / purpose' / coin_type' / account' / change / aadress_index
2279
- *
2280
- * see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
2281
- */
2282
- derivePath(path) {
2283
- return new MultiWallet(this.networkName, this.hdnode.derivePath(path))
2284
- }
2243
+ get message() {
2244
+ return {
2245
+ /**
2246
+ * Get content for given message hash
2247
+ *
2248
+ * @param {String} hash
2249
+ */
2250
+ get: async (hash) => {
2251
+ debug(`get message ${hash}`);
2252
+ const message = await messageStore.has(hash);
2253
+ if (message) return await messageStore.get(hash)
2254
+ return this.requestData(hash, 'message')
2255
+ },
2256
+ /**
2257
+ * put message content
2258
+ *
2259
+ * @param {String} hash
2260
+ * @param {Buffer} message
2261
+ */
2262
+ put: async (hash, message) => await messageStore.put(hash, message),
2263
+ /**
2264
+ * @param {String} hash
2265
+ * @return {Boolean}
2266
+ */
2267
+ has: async (hash) => await messageStore.has(hash),
2268
+ }
2269
+ }
2285
2270
 
2286
- derive(index) {
2287
- return new MultiWallet(this.networkName, this.hdnode.derive(index));
2288
- }
2289
- }
2290
-
2291
- class MessageHandler {
2292
- constructor(network) {
2293
- this.network = network;
2271
+ get data() {
2272
+ return {
2273
+ /**
2274
+ * Get content for given data hash
2275
+ *
2276
+ * @param {String} hash
2277
+ */
2278
+ get: async (hash) => {
2279
+ debug(`get data ${hash}`);
2280
+ const data = await dataStore.has(hash);
2281
+ if (data) return await dataStore.get(hash)
2282
+ return this.requestData(hash, 'data')
2283
+ },
2284
+ /**
2285
+ * put data content
2286
+ *
2287
+ * @param {String} hash
2288
+ * @param {Buffer} data
2289
+ */
2290
+ put: async (hash, data) => await dataStore.put(hash, data),
2291
+ /**
2292
+ * @param {String} hash
2293
+ * @return {Boolean}
2294
+ */
2295
+ has: async (hash) => await dataStore.has(hash),
2296
+ }
2294
2297
  }
2298
+
2295
2299
  /**
2296
- * hash and sign message
2297
- *
2298
- * @param {object} message
2299
- * @param {Buffer} message.from peer id
2300
- * @param {Buffer} message.to peer id
2301
- * @param {string} message.data Peernet message
2302
- * (PeernetMessage excluded) encoded as a string
2303
- * @return signature
2300
+ * goes trough given stores and tries to find data for given hash
2301
+ * @param {Array} stores
2302
+ * @param {string} hash
2304
2303
  */
2305
- async hashAndSignMessage(message) {
2306
- const hasher = new PeernetHash(message, {name: 'peernet-message'});
2307
- let identity = await walletStore.get('identity');
2308
- identity = JSON.parse(new TextDecoder().decode(identity));
2309
- const wallet = new MultiWallet(this.network);
2310
- wallet.recover(identity.mnemonic);
2311
- return wallet.sign(Buffer.from(hasher.hash).slice(0, 32))
2304
+ async whichStore(stores, hash) {
2305
+ let store = stores.pop();
2306
+ store = globalThis[`${store}Store`];
2307
+ if (store) {
2308
+ const has = await store.has(hash);
2309
+ if (has) return store
2310
+ if (stores.length > 0) return this.whichStore(stores, hash)
2311
+ } else return null
2312
2312
  }
2313
2313
 
2314
2314
  /**
2315
- * @param {String} from - peer id
2316
- * @param {String} to - peer id
2317
- * @param {String|PeernetMessage} data - data encoded message string
2318
- * or the messageNode itself
2315
+ * Get content for given hash
2316
+ *
2317
+ * @param {String} hash - the hash of the wanted data
2318
+ * @param {String} store - storeName to access
2319
2319
  */
2320
- async prepareMessage(from, to, data, id) {
2321
- if (data.encoded) data = data.encoded;
2320
+ async get(hash, store) {
2321
+ debug(`get ${hash}`);
2322
+ let data;
2323
+ if (store) store = globalThis[`${store}Store`];
2324
+ if (!store) store = await this.whichStore([...this.stores], hash);
2325
+ if (store && await store.has(hash)) data = await store.get(hash);
2326
+ if (data) return data
2322
2327
 
2323
- const message = {
2324
- from,
2325
- to,
2326
- data,
2327
- };
2328
- const signature = await this.hashAndSignMessage(message);
2329
- const node = new PeernetMessage({
2330
- ...message,
2331
- signature,
2332
- });
2328
+ return this.requestData(hash, store?.name ? store.name : store)
2329
+ }
2333
2330
 
2334
- return node
2331
+ /**
2332
+ * put content
2333
+ *
2334
+ * @param {String} hash
2335
+ * @param {Buffer} data
2336
+ * @param {String} store - storeName to access
2337
+ */
2338
+ async put(hash, data, store = 'data') {
2339
+ store = globalThis[`${store}Store`];
2340
+ return store.put(hash, data)
2335
2341
  }
2336
- }
2337
-
2338
- const dataHandler = async message => {
2339
- if (!message) return
2340
2342
 
2341
- const {data, id} = message;
2343
+ /**
2344
+ * @param {String} hash
2345
+ * @return {Boolean}
2346
+ */
2347
+ async has(hash) {
2348
+ const store = await this.whichStore([...this.stores], hash);
2349
+ if (store) {
2350
+ if (store.private) return false
2351
+ else return true
2352
+ }
2353
+ return false
2354
+ }
2342
2355
 
2343
- message = protoFor(data);
2344
- const proto = protoFor(message.decoded.data);
2345
- const from = message.decoded.from;
2356
+ /**
2357
+ *
2358
+ * @param {String} topic
2359
+ * @param {String|Object|Array|Boolean|Buffer} data
2360
+ */
2361
+ async publish(topic, data) {
2362
+ // globalSub.publish(topic, data)
2363
+ if (topic instanceof Uint8Array === false) topic = new TextEncoder().encode(topic);
2364
+ if (data instanceof Uint8Array === false) data = new TextEncoder().encode(JSON.stringify(data));
2365
+ const id = Math.random().toString(36).slice(-12);
2366
+ data = new PsMessage({data, topic});
2367
+ for (const peer of this.connections) {
2368
+ if (peer.peerId !== this.peerId) {
2369
+ const node = await this.prepareMessage(peer.peerId, data.encoded);
2370
+ this.sendMessage(peer, id, node.encoded);
2371
+ }
2372
+ // TODO: if peer subscribed
2373
+ }
2374
+ }
2346
2375
 
2347
- peernet._protoHandler({id, proto}, peernet.client.connections[from], from);
2348
- };
2349
-
2350
- const encapsulatedError = () => {
2351
- return new Error('Nodes/Data should be send encapsulated by peernet-message')
2352
- };
2353
-
2354
- const dhtError = (proto) => {
2355
- const text = `Received proto ${proto.name} expected peernet-dht-response`;
2356
- return new Error(`Routing error: ${text}`)
2357
- };
2358
-
2359
- const nothingFoundError = (hash) => {
2360
- return new Error(`nothing found for ${hash}`)
2361
- };
2362
-
2363
- globalThis.leofcoin = globalThis.leofcoin || {};
2364
- globalThis.globalSub = globalThis.globalSub || new PubSub({verbose: true});
2376
+ createHash(data, name) {
2377
+ return new codecFormatInterface.CodecHash(data, {name})
2378
+ }
2365
2379
 
2366
- /**
2367
- * @access public
2368
- * @example
2369
- * const peernet = new Peernet();
2370
- */
2371
- class Peernet {
2372
2380
  /**
2373
- * @access public
2374
- * @param {Object} options
2375
- * @param {String} options.network - desired network
2376
- * @param {String} options.root - path to root directory
2377
- * @param {String} options.storePrefix - prefix for datatores (lfc)
2378
- *
2379
- * @return {Promise} instance of Peernet
2380
2381
  *
2381
- * @example
2382
- * const peernet = new Peernet({network: 'leofcoin', root: '.leofcoin'});
2382
+ * @param {String} topic
2383
+ * @param {Method} cb
2383
2384
  */
2384
- constructor(options = {}) {
2385
- this._discovered = [];
2386
- /**
2387
- * @property {String} network - current network
2388
- */
2389
- this.network = options.network || 'leofcoin';
2390
- const parts = this.network.split(':');
2385
+ async subscribe(topic, cb) {
2386
+ // TODO: if peer subscribed
2387
+ globalSub.subscribe(topic, cb);
2388
+ }
2391
2389
 
2392
- if (!options.storePrefix) options.storePrefix = 'lfc';
2393
- if (!options.port) options.port = 2000;
2394
- if (!options.root) {
2395
- if (parts[1]) options.root = `.${parts[0]}/peernet/${parts[1]}`;
2396
- else options.root = `.${this.network}/peernet`;
2397
- }
2398
- globalThis.peernet = this;
2399
- this.bw = {
2400
- up: 0,
2401
- down: 0,
2402
- };
2403
- return this._init(options)
2390
+ async removePeer(peer) {
2391
+ return this.client.removePeer(peer)
2404
2392
  }
2405
2393
 
2406
- get defaultStores() {
2407
- return ['account', 'wallet', 'block', 'transaction', 'chain', 'data', 'message']
2394
+ get Buffer() {
2395
+ return Buffer
2408
2396
  }
2397
+ // async block(index) {
2398
+ // const _values = []
2399
+ // for (const peer of this.peers) {
2400
+ // const value = await peer.request({type: 'block', index})
2401
+ // console.log(value);
2402
+ // }
2403
+ //
2404
+ // }
2405
+ }
2406
+
2407
+ module.exports = Peernet;
2408
+
2409
+
2410
+ /***/ }),
2411
+
2412
+ /***/ 5698:
2413
+ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
2414
+
2415
+ "use strict";
2416
+ // ESM COMPAT FLAG
2417
+ __webpack_require__.r(__webpack_exports__);
2418
+
2419
+ // EXPORTS
2420
+ __webpack_require__.d(__webpack_exports__, {
2421
+ "default": function() { return /* binding */ src; }
2422
+ });
2423
+
2424
+ // EXTERNAL MODULE: ./node_modules/@vandeurenglenn/base32/src/base32.js
2425
+ var src_base32 = __webpack_require__(103);
2426
+ // EXTERNAL MODULE: ./node_modules/@vandeurenglenn/base58/src/base58.js
2427
+ var src_base58 = __webpack_require__(158);
2428
+ ;// CONCATENATED MODULE: ./node_modules/@vandeurenglenn/is-hex/is-hex.js
2429
+ /* harmony default export */ var is_hex = (string => /^[A-F0-9]+$/i.test(string));
2430
+
2431
+ ;// CONCATENATED MODULE: ./node_modules/@leofcoin/codec-format-interface/src/basic-interface.js
2432
+ /* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"];
2409
2433
 
2410
- addProto(name, proto) {
2411
- if (!this.protos[name]) this.protos[name] = proto;
2434
+
2435
+
2436
+
2437
+ class BasicInterface {
2438
+ #handleDecode() {
2439
+ if (!this.decode) throw new Error('bad implementation: needs decode func')
2440
+ this.decode()
2412
2441
  }
2413
2442
 
2414
- addCodec(name, codec) {
2415
- if (!this.codecs[name]) this.codecs[name] = codec;
2443
+ #handleEncode() {
2444
+ if (!this.encode) throw new Error('bad implementation: needs encode func')
2445
+ this.encode()
2446
+ }
2447
+ isHex(string) {
2448
+ return is_hex(string)
2449
+ }
2450
+ isBase32(string) {
2451
+ return base32.isBase32(string)
2452
+ }
2453
+ isBase58(string) {
2454
+ return base58.isBase32(string)
2455
+ }
2456
+ /**
2457
+ * @param {String} encoded
2458
+ */
2459
+ fromBs32(encoded) {
2460
+ this.encoded = src_base32/* default.decode */.Z.decode(encoded)
2461
+ return this.#handleDecode()
2416
2462
  }
2417
2463
 
2418
- async addStore(name, prefix, root, isPrivate = true) {
2419
- if (name === 'block' || name === 'transaction' || name === 'chain' ||
2420
- name === 'data' || name === 'message') isPrivate = false;
2464
+ /**
2465
+ * @param {String} encoded
2466
+ */
2467
+ fromBs58(encoded) {
2468
+ this.encoded = src_base58/* default.decode */.Z.decode(encoded)
2469
+ return this.#handleDecode()
2470
+ }
2421
2471
 
2422
- let Storage;
2423
- if (this.hasDaemon) {
2424
- Storage = LeofcoinStorageClient;
2425
- } else {
2426
- Storage = globalThis.LeofcoinStorage?.default ? globalThis.LeofcoinStorage.default : LeofcoinStorage__default["default"];
2472
+ async toArray() {
2473
+ const array = []
2474
+ for await (const value of this.encoded.values()) {
2475
+ array.push(value)
2427
2476
  }
2428
- globalThis[`${name}Store`] = globalThis[`${name}Store`] ||
2429
- await new Storage(name, root);
2477
+ return array
2478
+ }
2430
2479
 
2431
- globalThis[`${name}Store`].private = isPrivate;
2432
- if (!isPrivate) this.stores.push(name);
2480
+ fromString(string) {
2481
+ this.encoded = new Uint8Array(string.split(','))
2482
+ return this.#handleDecode()
2433
2483
  }
2434
2484
 
2485
+ fromArray(array) {
2486
+ this.encoded = new Uint8Array([...array])
2487
+ return this.#handleDecode()
2488
+ }
2435
2489
 
2436
2490
  /**
2437
- * @see MessageHandler
2491
+ * @param {Buffer} encoded
2438
2492
  */
2439
- prepareMessage(to, data) {
2440
- return this._messageHandler.prepareMessage(this.id, to, data)
2493
+ fromEncoded(encoded) {
2494
+ this.encoded = encoded
2495
+ return this.#handleDecode()
2441
2496
  }
2442
2497
 
2443
2498
  /**
2444
- * @access public
2445
- *
2446
- * @return {Array} peerId
2499
+ * @param {String} encoded
2447
2500
  */
2448
- get peers() {
2449
- return Object.keys(this.client.connections)
2501
+ fromHex(encoded) {
2502
+ this.encoded = Buffer.from(encoded, 'hex')
2503
+ return this.#handleDecode()
2450
2504
  }
2451
2505
 
2452
- get connections() {
2453
- return Object.values(this.client.connections)
2506
+ toString(encoding = 'utf8') {
2507
+ if (!this.encoded) this.#handleEncode()
2508
+ return this.encoded.toString(encoding)
2454
2509
  }
2455
2510
 
2456
- get peerEntries() {
2457
- return Object.entries(this.client.connections)
2511
+ /**
2512
+ * @return {String} encoded
2513
+ */
2514
+ toHex() {
2515
+ return this.toString('hex')
2458
2516
  }
2459
2517
 
2460
2518
  /**
2461
- * @return {String} id - peerId
2519
+ * @return {String} encoded
2462
2520
  */
2463
- getConnection(id) {
2464
- return this.client.connections[id]
2521
+ toBs32() {
2522
+ if (!this.encoded) this.#handleEncode()
2523
+ return src_base32/* default.encode */.Z.encode(this.encoded)
2465
2524
  }
2466
2525
 
2467
2526
  /**
2468
- * @private
2469
- *
2470
- * @param {Object} options
2471
- * @param {String} options.root - path to root directory
2472
- *
2473
- * @return {Promise} instance of Peernet
2527
+ * @return {String} encoded
2474
2528
  */
2475
- async _init(options) {
2476
- // peernetDHT aka closesPeer by coordinates
2477
- /**
2478
- * @type {Object}
2479
- * @property {Object} peer Instance of Peer
2480
- */
2481
- this.dht = new DhtEarth();
2482
- /**
2483
- * @type {Map}
2484
- * @property {Object} peer Instance of Peer
2485
- */
2486
- this.stores = [];
2487
- this.requestProtos = {};
2488
- this.storePrefix = options.storePrefix;
2489
- this.root = options.root;
2490
-
2491
- /**
2492
- * proto Object containing protos
2493
- * @type {Object}
2494
- * @property {PeernetMessage} protos[peernet-message] messageNode
2495
- * @property {DHTMessage} protos[peernet-dht] messageNode
2496
- * @property {DHTMessageResponse} protos[peernet-dht-response] messageNode
2497
- * @property {DataMessage} protos[peernet-data] messageNode
2498
- * @property {DataMessageResponse} protos[peernet-data-response] messageNode
2499
- */
2500
- globalThis.peernet.protos = {
2501
- 'peernet-request': RequestMessage,
2502
- 'peernet-response': ResponseMessage,
2503
- 'peernet-peer': PeerMessage,
2504
- 'peernet-peer-response': PeerMessageResponse,
2505
- 'peernet-message': PeernetMessage,
2506
- 'peernet-dht': DHTMessage,
2507
- 'peernet-dht-response': DHTMessageResponse,
2508
- 'peernet-data': DataMessage,
2509
- 'peernet-data-response': DataMessageResponse,
2510
- 'peernet-ps': PsMessage,
2511
- 'chat-message': ChatMessage,
2512
- };
2529
+ toBs58() {
2530
+ if (!this.encoded) this.#handleEncode()
2531
+ return src_base58/* default.encode */.Z.encode(this.encoded)
2532
+ }
2513
2533
 
2514
- this.protos = globalThis.peernet.protos;
2515
- this.codecs = codecs;
2534
+ /**
2535
+ * @param {Object} data
2536
+ */
2537
+ create(data) {
2538
+ const decoded = {}
2539
+ if (this.keys?.length > 0) {
2540
+ for (const key of this.keys) {
2541
+ Object.defineProperties(decoded, {
2542
+ [key]: {
2543
+ enumerable: true,
2544
+ configurable: true,
2545
+ set: (val) => value = data[key],
2546
+ get: () => data[key]
2547
+ }
2548
+ })
2549
+ }
2516
2550
 
2517
- this._messageHandler = new MessageHandler(this.network);
2551
+ this.decoded = decoded
2552
+ this.encode()
2553
+ }
2554
+ }
2555
+ }
2556
+
2557
+ // EXTERNAL MODULE: ./node_modules/varint/index.js
2558
+ var varint = __webpack_require__(4676);
2559
+ var varint_default = /*#__PURE__*/__webpack_require__.n(varint);
2560
+ ;// CONCATENATED MODULE: ./node_modules/@leofcoin/codec-format-interface/src/codecs.js
2561
+ /* harmony default export */ var codecs = ({
2562
+ // just a hash
2563
+ 'disco-hash': {
2564
+ codec: parseInt('30', 16),
2565
+ hashAlg: 'dbl-keccak-256', // ,
2566
+ // testnet: 'olivia'
2567
+ },
2568
+ 'peernet-peer-response': {
2569
+ codec: parseInt('707072', 16),
2570
+ hashAlg: 'keccak-256',
2571
+ },
2572
+ 'peernet-peer': {
2573
+ codec: parseInt('7070', 16),
2574
+ hashAlg: 'keccak-256',
2575
+ },
2576
+ 'peernet-dht': {
2577
+ codec: parseInt('706468', 16),
2578
+ hashAlg: 'keccak-256',
2579
+ },
2580
+ 'peernet-dht-response': {
2581
+ codec: parseInt('706472', 16),
2582
+ hashAlg: 'keccak-256',
2583
+ },
2584
+ // data
2585
+ 'peernet-data': {
2586
+ codec: parseInt('706461', 16),
2587
+ hashAlg: 'keccak-256',
2588
+ },
2589
+ 'peernet-data-response': {
2590
+ codec: parseInt('70646172', 16),
2591
+ hashAlg: 'keccak-256',
2592
+ },
2593
+ // message
2594
+ 'peernet-message': {
2595
+ codec: parseInt('706d65', 16),
2596
+ hashAlg: 'keccak-256',
2597
+ },
2598
+ // pubsub
2599
+ 'peernet-ps': {
2600
+ codec: parseInt('707073', 16),
2601
+ hashAlg: 'keccak-256',
2602
+ },
2603
+ 'peernet-response': {
2604
+ codec: parseInt('7072', 16),
2605
+ hashAlg: 'keccak-256',
2606
+ },
2607
+ 'peernet-request': {
2608
+ codec: parseInt('707271', 16),
2609
+ hashAlg: 'keccak-256',
2610
+ },
2611
+ // normal block
2612
+ 'leofcoin-block': {
2613
+ codec: parseInt('6c62', 16),
2614
+ hashAlg: 'dbl-keccak-512', // ,
2615
+ // testnet: 'olivia'
2616
+ },
2617
+ 'leofcoin-tx': {
2618
+ codec: parseInt('6c74', 16),
2619
+ hashAlg: 'dbl-keccak-512', // ,
2620
+ // testnet: 'olivia'
2621
+ },
2622
+ // itx
2623
+ 'leofcoin-itx': {
2624
+ codec: parseInt('6c69', 16),
2625
+ hashAlg: 'keccak-512', // ,
2626
+ // testnet: 'olivia'
2627
+ },
2628
+ // peer reputation
2629
+ 'leofcoin-pr': {
2630
+ codec: parseInt('6c70', 16),
2631
+ hashAlg: 'keccak-256', // ,
2632
+ // testnet: 'olivia'
2633
+ },
2634
+ // chat message
2635
+ 'chat-message': {
2636
+ codec: parseInt('636d', 16),
2637
+ hashAlg: 'dbl-keccak-256',
2638
+ },
2639
+ });
2640
+
2641
+ ;// CONCATENATED MODULE: ./node_modules/@leofcoin/codec-format-interface/src/codec.js
2518
2642
 
2519
- const {daemon, environment} = await target();
2520
- this.hasDaemon = daemon;
2521
2643
 
2522
-
2523
2644
 
2524
- for (const store of this.defaultStores) {
2525
- await this.addStore(store, options.storePrefix, options.root);
2526
- }
2527
2645
 
2528
- try {
2529
- const pub = await accountStore.get('public');
2530
- this.id = JSON.parse(new TextDecoder().decode(pub)).walletId;
2531
- } catch (e) {
2532
- if (e.code === 'ERR_NOT_FOUND') {
2533
- const {identity, accounts, config} = await generateAccount(this.network);
2534
- walletStore.put('version', new TextEncoder().encode(1));
2535
- walletStore.put('accounts', new TextEncoder().encode(accounts));
2536
- walletStore.put('identity', new TextEncoder().encode(JSON.stringify(identity)));
2537
- await accountStore.put('config', new TextEncoder().encode(JSON.stringify(config)));
2538
- await accountStore.put('public', new TextEncoder().encode(JSON.stringify({walletId: identity.walletId})));
2646
+ class PeernetCodec extends BasicInterface {
2647
+ get codecs() {
2648
+ return {...globalThis.peernet.codecs, ...codecs}
2649
+ }
2650
+ constructor(buffer) {
2651
+ super()
2652
+ if (buffer) {
2653
+ if (buffer instanceof Uint8Array) {
2654
+ const codec = varint_default().decode(buffer);
2655
+ const name = this.getCodecName(codec)
2656
+ if (name) {
2657
+ this.name = name
2658
+ this.encoded = buffer
2659
+ this.decode(buffer)
2660
+ } else {
2661
+ this.encode(buffer)
2662
+ }
2663
+ } else if (buffer instanceof ArrayBuffer) {
2664
+ const encoded = new Uint8Array(buffer.byteLength)
2539
2665
 
2540
- this.id = identity.walletId;
2541
- } else {
2542
- throw e
2666
+ for (let i = 0; i < buffer.byteLength; i++) {
2667
+ encoded[i] = buffer[i]
2668
+ }
2669
+ this.encoded = encoded
2670
+ // this.encoded = new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength)
2671
+ this.decode(buffer)
2672
+ return
2673
+ }
2674
+ if (typeof buffer === 'string') {
2675
+ if (this.codecs[buffer]) this.fromName(buffer)
2676
+ else if (this.isHex(buffer)) this.fromHex(buffer)
2677
+ else if (this.isBase32(buffer)) this.fromBs32(buffer)
2678
+ else if (this.isBase58(buffer)) this.fromBs58(buffer)
2679
+ else throw new Error(`unsupported string ${buffer}`)
2543
2680
  }
2681
+ if (!isNaN(buffer)) if (this.codecs[this.getCodecName(buffer)]) this.fromCodec(buffer)
2544
2682
  }
2545
- this._peerHandler = new PeerDiscovery(this.id);
2546
- this.peerId = this.id;
2683
+ }
2547
2684
 
2548
- pubsub.subscribe('peer:connected', async (peer) => {
2549
- console.log(peer);
2550
- // console.log({connected: peer.id, as: this._getPeerId(peer.id) });
2551
- // peer.on('peernet.data', async (message) => {
2552
- // const id = message.id
2553
- // message = new PeernetMessage(Buffer.from(message.data.data))
2554
- // const proto = protoFor(message.decoded.data)
2555
- // this._protoHandler({id, proto}, peer)
2556
- // })
2557
- });
2685
+ fromEncoded(encoded) {
2686
+ const codec = varint_default().decode(encoded);
2687
+ const name = this.getCodecName(codec)
2688
+ this.name = name
2689
+ this.encoded = encoded
2690
+ this.decode(encoded)
2691
+ }
2558
2692
 
2559
- /**
2560
- * converts data -> message -> proto
2561
- * @see DataHandler
2562
- */
2563
- pubsub.subscribe('peer:data', dataHandler);
2693
+ getCodec(name) {
2694
+ return this.codecs[name].codec
2695
+ }
2564
2696
 
2565
- /**
2566
- * @access public
2567
- * @type {PeernetClient}
2568
- */
2569
- this.client = new Client(this.id);
2570
- if (globalThis.onbeforeunload) {
2571
- globalThis.addEventListener('beforeunload', async () => this.client.close());
2572
- }
2573
- return this
2697
+ getCodecName(codec) {
2698
+ return Object.keys(this.codecs).reduce((p, c) => {
2699
+ const item = this.codecs[c]
2700
+ if (item.codec === codec) return c;
2701
+ else return p;
2702
+ }, undefined)
2574
2703
  }
2575
2704
 
2576
- addRequestHandler(name, method) {
2577
- this.requestProtos[name] = method;
2705
+ getHashAlg(name) {
2706
+ return this.codecs[name].hashAlg
2578
2707
  }
2579
2708
 
2580
- sendMessage(peer, id, data) {
2581
- if (peer.readyState === 'open') {
2582
- peer.send(data, id);
2583
- this.bw.up += data.length;
2584
- } else if (peer.readyState === 'closed') ;
2709
+ fromCodec(codec) {
2710
+ this.name = this.getCodecName(codec)
2711
+ this.hashAlg = this.getHashAlg(this.name)
2585
2712
 
2713
+ this.codec = this.getCodec(this.name)
2714
+ this.codecBuffer = varint_default().encode(codec)
2586
2715
  }
2587
2716
 
2588
- /**
2589
- * @private
2590
- *
2591
- * @param {Buffer} message - peernet message
2592
- * @param {PeernetPeer} peer - peernet peer
2593
- */
2594
- async _protoHandler(message, peer, from) {
2717
+ fromName(name) {
2718
+ const codec = this.getCodec(name)
2719
+ this.name = name
2720
+ this.codec = codec
2721
+ this.hashAlg = this.getHashAlg(name)
2722
+ this.codecBuffer = varint_default().encode(codec)
2723
+ }
2595
2724
 
2596
- const {id, proto} = message;
2597
- this.bw.down += proto.encoded.length;
2598
- if (proto.name === 'peernet-dht') {
2599
- let { hash, store } = proto.decoded;
2600
- let has;
2725
+ decode() {
2726
+ const codec = varint_default().decode(this.encoded);
2727
+ this.fromCodec(codec)
2728
+ }
2601
2729
 
2602
- if (!store) {
2603
- has = await this.has(hash);
2604
- } else {
2605
- store = globalThis[`${store}Store`];
2606
- if (store.private) has = false;
2607
- else has = await store.has(hash);
2608
- }
2609
- const data = new DHTMessageResponse({hash, has});
2610
- const node = await this.prepareMessage(from, data.encoded);
2730
+ encode() {
2731
+ const codec = varint_default().encode(this.decoded)
2732
+ this.encoded = codec
2733
+ return this.encoded
2734
+ }
2735
+ }
2736
+
2737
+ // EXTERNAL MODULE: ./node_modules/keccak/js.js
2738
+ var js = __webpack_require__(5811);
2739
+ var js_default = /*#__PURE__*/__webpack_require__.n(js);
2740
+ ;// CONCATENATED MODULE: ./node_modules/@leofcoin/codec-format-interface/src/codec-hash.js
2741
+ /* provided dependency */ var codec_hash_Buffer = __webpack_require__(8764)["Buffer"];
2611
2742
 
2612
- this.sendMessage(peer, id, node.encoded);
2613
- } else if (proto.name === 'peernet-data') {
2614
- let { hash, store } = proto.decoded;
2615
- let data;
2616
- if (!store) {
2617
- store = await this.whichStore([...this.stores], hash);
2618
- } else {
2619
- store = globalThis[`${store}Store`];
2620
- }
2621
- if (store && !store.private) {
2622
- data = await store.get(hash);
2623
2743
 
2624
- if (data) {
2625
- data = new DataMessageResponse({hash, data});
2626
2744
 
2627
- const node = await this.prepareMessage(from, data.encoded);
2628
- this.sendMessage(peer, id, node.encoded);
2629
- }
2630
- }
2631
2745
 
2632
- } else if (proto.name === 'peernet-request') {
2633
- const method = this.requestProtos[proto.decoded.request];
2634
- if (method) {
2635
- const data = await method();
2636
- const node = await this.prepareMessage(from, data.encoded);
2637
- this.sendMessage(peer, id, node.encoded);
2746
+
2747
+ class CodecHash extends BasicInterface {
2748
+ constructor(buffer, options = {}) {
2749
+ super()
2750
+ if (options.name) this.name = options.name
2751
+ else this.name = 'disco-hash'
2752
+ if (options.codecs) this.codecs = options.codecs
2753
+ if (buffer) {
2754
+ if (buffer instanceof Uint8Array) {
2755
+ this.discoCodec = new PeernetCodec(buffer, this.codecs)
2756
+ const name = this.discoCodec.name
2757
+
2758
+ if (name) {
2759
+ this.name = name
2760
+ this.decode(buffer)
2761
+ } else {
2762
+ this.encode(buffer)
2638
2763
  }
2639
- } else if (proto.name === 'peernet-ps' && peer.peerId !== this.id) {
2640
- globalSub.publish(new TextDecoder().decode(proto.decoded.topic), proto.decoded.data);
2641
2764
  }
2642
- // }
2643
- }
2644
2765
 
2645
- /**
2646
- * performs a walk and resolves first encounter
2647
- *
2648
- * @param {String} hash
2649
- */
2650
- async walk(hash) {
2651
- if (!hash) throw new Error('hash expected, received undefined')
2652
- const data = new DHTMessage({hash});
2653
- this.client.id;
2654
- const walk = async peer => {
2655
- const node = await this.prepareMessage(peer.peerId, data.encoded);
2656
- let result = await peer.request(node.encoded);
2657
- result = new Uint8Array(Object.values(result));
2658
- let proto = protoFor(result);
2659
- if (proto.name !== 'peernet-message') throw encapsulatedError()
2660
- const from = proto.decoded.from;
2661
- proto = protoFor(proto.decoded.data);
2662
- if (proto.name !== 'peernet-dht-response') throw dhtError(proto.name)
2766
+ if (typeof buffer === 'string') {
2767
+ if (this.isHex(buffer)) this.fromHex(buffer)
2768
+ if (this.isBase32(buffer)) this.fromBs32(buffer)
2769
+ else if (this.isBase58(buffer)) this.fromBs58(buffer)
2770
+ else throw new Error(`unsupported string ${buffer}`)
2771
+ } else if (typeof buffer === 'object') this.fromJSON(buffer)
2772
+ }
2773
+ }
2663
2774
 
2664
- // TODO: give ip and port (just used for location)
2665
- if (!peer.connection.remoteAddress || !peer.connection.localAddress) {
2666
- peer.connection.remoteFamily = 'ipv4';
2667
- peer.connection.remoteAddress = '127.0.0.1';
2668
- peer.connection.remotePort = '0000';
2669
- }
2775
+ get prefix() {
2776
+ const length = this.length
2777
+ const uint8Array = new Uint8Array(length.length + this.discoCodec.codecBuffer.length)
2778
+ uint8Array.set(length)
2779
+ uint8Array.set(this.discoCodec.codecBuffer, length.length)
2670
2780
 
2671
- const peerInfo = {
2672
- family: peer.connection.remoteFamily || peer.connection.localFamily,
2673
- address: peer.connection.remoteAddress || peer.connection.localAddress,
2674
- port: peer.connection.remotePort || peer.connection.localPort,
2675
- id: from,
2676
- };
2781
+ return uint8Array
2782
+ }
2677
2783
 
2678
- if (proto.decoded.has) this.dht.addProvider(peerInfo, proto.decoded.hash);
2679
- };
2680
- let walks = [];
2681
- for (const peer of this.connections) {
2682
- if (peer.peerId !== this.id) {
2683
- walks.push(walk(peer));
2684
- }
2685
- }
2686
- return Promise.all(walks)
2784
+ get length() {
2785
+ return varint_default().encode(this.size)
2687
2786
  }
2688
2787
 
2689
- /**
2690
- * Override DHT behavior, try's finding the content three times
2691
- *
2692
- * @param {String} hash
2693
- */
2694
- async providersFor(hash) {
2695
- let providers = await this.dht.providersFor(hash);
2696
- // walk the network to find a provider
2697
- if (!providers || providers.length === 0) {
2698
- await this.walk(hash);
2699
- providers = await this.dht.providersFor(hash);
2700
- // second walk the network to find a provider
2701
- if (!providers || providers.length === 0) {
2702
- await this.walk(hash);
2703
- providers = await this.dht.providersFor(hash);
2704
- }
2705
- // last walk
2706
- if (!providers || providers.length === 0) {
2707
- await this.walk(hash);
2708
- providers = await this.dht.providersFor(hash);
2709
- }
2710
- }
2711
- // undefined if no providers given
2712
- return providers
2788
+ get buffer() {
2789
+ return this.encoded
2713
2790
  }
2714
2791
 
2715
- get block() {
2716
- return {
2717
- get: async (hash) => {
2718
- const data = await blockStore.has(hash);
2719
- if (data) return await blockStore.get(hash)
2720
- return this.requestData(hash, 'block')
2721
- },
2722
- put: async (hash, data) => {
2723
- if (await blockStore.has(hash)) return
2724
- return await blockStore.put(hash, data)
2725
- },
2726
- has: async (hash) => await blockStore.has(hash, 'block'),
2727
- }
2792
+ get hash() {
2793
+ return this.encoded
2728
2794
  }
2729
2795
 
2730
- get transaction() {
2731
- return {
2732
- get: async (hash) => {
2733
- const data = await transactionStore.has(hash);
2734
- if (data) return await transactionStore.get(hash)
2735
- return this.requestData(hash, 'transaction')
2736
- },
2737
- put: async (hash, data) => {
2738
- if (await transactionStore.has(hash)) return
2739
- return await transactionStore.put(hash, data)
2740
- },
2741
- has: async (hash) => await transactionStore.has(hash),
2742
- }
2796
+ fromJSON(json) {
2797
+ return this.encode(codec_hash_Buffer.from(JSON.stringify(json)))
2743
2798
  }
2744
2799
 
2745
- async requestData(hash, store) {
2746
- const providers = await this.providersFor(hash);
2747
- if (!providers || providers.size === 0) throw nothingFoundError(hash)
2748
- debug(`found ${providers.size} provider(s) for ${hash}`);
2749
- // get closest peer on earth
2750
- const closestPeer = await this.dht.closestPeer(providers);
2751
- // get peer instance by id
2752
- if (!closestPeer || !closestPeer.id) return this.requestData(hash, store?.name ? store?.name : store)
2800
+ encode(buffer, name) {
2801
+ if (!this.name && name) this.name = name;
2802
+ if (!buffer) buffer = this.buffer;
2803
+ this.discoCodec = new PeernetCodec(this.name, this.codecs)
2804
+ this.discoCodec.fromName(this.name)
2805
+ let hashAlg = this.discoCodec.hashAlg
2806
+ if (hashAlg.includes('dbl')) {
2807
+ hashAlg = hashAlg.replace('dbl-', '')
2808
+ buffer = js_default()(hashAlg.replace('-', '')).update(buffer).digest()
2809
+ }
2810
+ this.digest = js_default()(hashAlg.replace('-', '')).update(buffer).digest()
2811
+ this.size = this.digest.length
2753
2812
 
2754
- const id = closestPeer.id;
2755
- if (this.connections) {
2756
- let closest = this.connections.filter((peer) => {
2757
- if (peer.peerId === id) return peer
2758
- });
2813
+ this.codec = this.discoCodec.encode();
2814
+ this.codec = this.discoCodec.codecBuffer
2815
+ const uint8Array = new Uint8Array(this.digest.length + this.prefix.length)
2816
+ uint8Array.set(this.prefix)
2817
+ uint8Array.set(this.digest, this.prefix.length)
2759
2818
 
2760
- let data = new DataMessage({hash, store: store?.name ? store?.name : store});
2819
+ this.encoded = uint8Array
2761
2820
 
2762
- const node = await this.prepareMessage(id, data.encoded);
2763
- if (closest[0]) data = await closest[0].request(node.encoded);
2764
- else {
2765
- closest = this.connections.filter((peer) => {
2766
- if (peer.peerId === id) return peer
2767
- });
2768
- if (closest[0]) data = await closest[0].request(node.encoded);
2769
- }
2770
- data = new Uint8Array(Object.values(data));
2771
- let proto = protoFor(data);
2772
- proto = protoFor(proto.decoded.data);
2773
- // TODO: store data automaticly or not
2774
- return proto.decoded.data
2821
+ return this.encoded
2822
+ }
2775
2823
 
2776
- // this.put(hash, proto.decoded.data)
2824
+ validate(buffer) {
2825
+ if (codec_hash_Buffer.isBuffer(buffer)) {
2826
+ const codec = varint_default().decode(buffer);
2827
+ if (this.codecs[codec]) {
2828
+ this.decode(buffer)
2829
+ } else {
2830
+ this.encode(buffer)
2831
+ }
2777
2832
  }
2778
- return null
2833
+ if (typeof buffer === 'string') {
2834
+ if (this.isHex(buffer)) this.fromHex(buffer)
2835
+ if (this.isBase32(buffer)) this.fromBs32(buffer)
2836
+ }
2837
+ if (typeof buffer === 'object') this.fromJSON(buffer)
2779
2838
  }
2780
2839
 
2840
+ decode(buffer) {
2841
+ this.encoded = buffer
2842
+ const codec = varint_default().decode(buffer);
2781
2843
 
2782
- get message() {
2783
- return {
2784
- /**
2785
- * Get content for given message hash
2786
- *
2787
- * @param {String} hash
2788
- */
2789
- get: async (hash) => {
2790
- debug(`get message ${hash}`);
2791
- const message = await messageStore.has(hash);
2792
- if (message) return await messageStore.get(hash)
2793
- return this.requestData(hash, 'message')
2794
- },
2795
- /**
2796
- * put message content
2797
- *
2798
- * @param {String} hash
2799
- * @param {Buffer} message
2800
- */
2801
- put: async (hash, message) => await messageStore.put(hash, message),
2802
- /**
2803
- * @param {String} hash
2804
- * @return {Boolean}
2805
- */
2806
- has: async (hash) => await messageStore.has(hash),
2844
+ this.discoCodec = new PeernetCodec(codec, this.codecs)
2845
+ // TODO: validate codec
2846
+ buffer = buffer.slice((varint_default()).decode.bytes);
2847
+ this.size = varint_default().decode(buffer);
2848
+ this.digest = buffer.slice((varint_default()).decode.bytes);
2849
+ if (this.digest.length !== this.size) {
2850
+ throw new Error(`hash length inconsistent: 0x${this.encoded.toString('hex')}`)
2807
2851
  }
2808
- }
2809
2852
 
2810
- get data() {
2853
+ // const discoCodec = new Codec(codec, this.codecs)
2854
+
2855
+ this.name = this.discoCodec.name
2856
+
2857
+
2858
+ this.size = this.digest.length
2859
+
2811
2860
  return {
2812
- /**
2813
- * Get content for given data hash
2814
- *
2815
- * @param {String} hash
2816
- */
2817
- get: async (hash) => {
2818
- debug(`get data ${hash}`);
2819
- const data = await dataStore.has(hash);
2820
- if (data) return await dataStore.get(hash)
2821
- return this.requestData(hash, 'data')
2822
- },
2823
- /**
2824
- * put data content
2825
- *
2826
- * @param {String} hash
2827
- * @param {Buffer} data
2828
- */
2829
- put: async (hash, data) => await dataStore.put(hash, data),
2830
- /**
2831
- * @param {String} hash
2832
- * @return {Boolean}
2833
- */
2834
- has: async (hash) => await dataStore.has(hash),
2861
+ codec: this.codec,
2862
+ name: this.name,
2863
+ size: this.size,
2864
+ length: this.length,
2865
+ digest: this.digest,
2835
2866
  }
2836
2867
  }
2868
+ }
2869
+
2870
+ ;// CONCATENATED MODULE: ./node_modules/@leofcoin/codec-format-interface/src/codec-format-interface.js
2871
+
2837
2872
 
2873
+
2874
+
2875
+ class FormatInterface extends BasicInterface {
2838
2876
  /**
2839
- * goes trough given stores and tries to find data for given hash
2840
- * @param {Array} stores
2841
- * @param {string} hash
2877
+ * @param {Buffer|String|Object} buffer - data - The data needed to create the desired message
2878
+ * @param {Object} proto - {encode, decode}
2879
+ * @param {Object} options - {hashFormat, name}
2842
2880
  */
2843
- async whichStore(stores, hash) {
2844
- let store = stores.pop();
2845
- store = globalThis[`${store}Store`];
2846
- if (store) {
2847
- const has = await store.has(hash);
2848
- if (has) return store
2849
- if (stores.length > 0) return this.whichStore(stores, hash)
2850
- } else return null
2881
+ constructor(buffer, proto, options = {}) {
2882
+ super()
2883
+ this.protoEncode = proto.encode
2884
+ this.protoDecode = proto.decode
2885
+ this.hashFormat = options.hashFormat || 'bs32'
2886
+ if (options.name) this.name = options.name
2887
+ if (buffer instanceof Uint8Array) this.fromUint8Array(buffer)
2888
+ else if (buffer instanceof ArrayBuffer) this.fromArrayBuffer(buffer)
2889
+ else if (buffer.name === options.name) return buffer
2890
+ else if (buffer instanceof String) {
2891
+ if (this.isHex(buffer)) this.fromHex(buffer)
2892
+ else if (this.isBase32(buffer)) this.fromBs32(buffer)
2893
+ else if (this.isBase58(buffer)) this.fromBs58(buffer)
2894
+ else throw new Error(`unsupported string ${buffer}`)
2895
+ } else {
2896
+ this.create(buffer)
2897
+ }
2851
2898
  }
2852
2899
 
2853
2900
  /**
2854
- * Get content for given hash
2855
- *
2856
- * @param {String} hash - the hash of the wanted data
2857
- * @param {String} store - storeName to access
2901
+ * @return {PeernetHash}
2858
2902
  */
2859
- async get(hash, store) {
2860
- debug(`get ${hash}`);
2861
- let data;
2862
- if (store) store = globalThis[`${store}Store`];
2863
- if (!store) store = await this.whichStore([...this.stores], hash);
2864
- if (store && await store.has(hash)) data = await store.get(hash);
2865
- if (data) return data
2866
-
2867
- return this.requestData(hash, store?.name ? store.name : store)
2903
+ get peernetHash() {
2904
+ return new CodecHash(this.decoded, {name: this.name})
2868
2905
  }
2869
2906
 
2870
2907
  /**
2871
- * put content
2872
- *
2873
- * @param {String} hash
2874
- * @param {Buffer} data
2875
- * @param {String} store - storeName to access
2908
+ * @return {peernetHash}
2876
2909
  */
2877
- async put(hash, data, store = 'data') {
2878
- store = globalThis[`${store}Store`];
2879
- return store.put(hash, data)
2910
+ get hash() {
2911
+ const upper = this.hashFormat.charAt(0).toUpperCase()
2912
+ const format = `${upper}${this.hashFormat.substring(1, this.hashFormat.length)}`
2913
+ return this.peernetHash[`to${format}`]()
2880
2914
  }
2881
2915
 
2882
2916
  /**
2883
- * @param {String} hash
2884
- * @return {Boolean}
2917
+ * @return {Object}
2885
2918
  */
2886
- async has(hash) {
2887
- const store = await this.whichStore([...this.stores], hash);
2888
- if (store) {
2889
- if (store.private) return false
2890
- else return true
2891
- }
2892
- return false
2919
+ decode() {
2920
+ let encoded = this.encoded;
2921
+ const discoCodec = new PeernetCodec(this.encoded)
2922
+ encoded = encoded.slice(discoCodec.codecBuffer.length)
2923
+ this.name = discoCodec.name
2924
+ this.decoded = this.protoDecode(encoded)
2925
+ return this.decoded
2893
2926
  }
2894
2927
 
2895
2928
  /**
2896
- *
2897
- * @param {String} topic
2898
- * @param {String|Object|Array|Boolean|Buffer} data
2929
+ * @return {Buffer}
2899
2930
  */
2900
- async publish(topic, data) {
2901
- // globalSub.publish(topic, data)
2902
- if (topic instanceof Uint8Array === false) topic = new TextEncoder().encode(topic);
2903
- if (data instanceof Uint8Array === false) data = new TextEncoder().encode(JSON.stringify(data));
2904
- const id = Math.random().toString(36).slice(-12);
2905
- data = new PsMessage({data, topic});
2906
- for (const peer of this.connections) {
2907
- if (peer.peerId !== this.peerId) {
2908
- const node = await this.prepareMessage(peer.peerId, data.encoded);
2909
- this.sendMessage(peer, id, node.encoded);
2910
- }
2911
- // TODO: if peer subscribed
2912
- }
2913
- }
2914
-
2915
- createHash(data, name) {
2916
- return new PeernetHash(data, {name})
2931
+ encode(decoded) {
2932
+ if (!decoded) decoded = this.decoded;
2933
+ const codec = new PeernetCodec(this.name)
2934
+ const encoded = this.protoEncode(decoded)
2935
+ const uint8Array = new Uint8Array(encoded.length + codec.codecBuffer.length)
2936
+ uint8Array.set(codec.codecBuffer)
2937
+ uint8Array.set(encoded, codec.codecBuffer.length)
2938
+ this.encoded = uint8Array
2939
+ return this.encoded
2917
2940
  }
2918
2941
 
2919
- /**
2920
- *
2921
- * @param {String} topic
2922
- * @param {Method} cb
2923
- */
2924
- async subscribe(topic, cb) {
2925
- // TODO: if peer subscribed
2926
- globalSub.subscribe(topic, cb);
2942
+ hasCodec() {
2943
+ if (!this.encoded) return false
2944
+ const codec = new PeernetCodec(this.encoded)
2945
+ if (codec.name) return true
2927
2946
  }
2928
2947
 
2929
- async removePeer(peer) {
2930
- return this.client.removePeer(peer)
2948
+ fromUint8Array(buffer) {
2949
+ this.encoded = buffer
2950
+ if (!this.hasCodec()) this.create(
2951
+ JSON.parse(new TextDecoder().decode(this.encoded))
2952
+ )
2953
+ else this.decode()
2931
2954
  }
2932
2955
 
2933
- get Buffer() {
2934
- return Buffer
2956
+ fromArrayBuffer(buffer) {
2957
+ this.encoded = new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength)
2958
+ if (!this.hasCodec()) this.create(
2959
+ JSON.parse(new TextDecoder().decode(this.encoded))
2960
+ )
2961
+ else this.decode()
2935
2962
  }
2936
- // async block(index) {
2937
- // const _values = []
2938
- // for (const peer of this.peers) {
2939
- // const value = await peer.request({type: 'block', index})
2940
- // console.log(value);
2941
- // }
2942
- //
2943
- // }
2944
- }
2963
+ }
2945
2964
 
2946
- module.exports = Peernet;
2965
+ ;// CONCATENATED MODULE: ./node_modules/@leofcoin/codec-format-interface/src/index.js
2966
+
2967
+
2968
+
2969
+
2970
+
2971
+
2972
+ /* harmony default export */ var src = ({ codecs: codecs, Codec: PeernetCodec, CodecHash: CodecHash, FormatInterface: FormatInterface, BasicInterface: BasicInterface });
2947
2973
 
2948
2974
 
2949
2975
  /***/ }),
@@ -3185,7 +3211,6 @@ const base = ALPHABET => {
3185
3211
  /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
3186
3212
 
3187
3213
  "use strict";
3188
- __webpack_require__.r(__webpack_exports__);
3189
3214
  /* harmony import */ var _vandeurenglenn_base_x__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2353);
3190
3215
 
3191
3216
 
@@ -3197,7 +3222,7 @@ const decode = (uint8Array, hex = false) => {
3197
3222
  return decoder.decode(uint8Array)
3198
3223
  }
3199
3224
 
3200
- /* harmony default export */ __webpack_exports__["default"] = ({
3225
+ /* harmony default export */ __webpack_exports__["Z"] = ({
3201
3226
  encode: (uint8Array, hex = false) => {
3202
3227
  const encoder = hex ? (0,_vandeurenglenn_base_x__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z)(base32Hex) : (0,_vandeurenglenn_base_x__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z)(base32)
3203
3228
  return encoder.encode(uint8Array)
@@ -3220,7 +3245,6 @@ const decode = (uint8Array, hex = false) => {
3220
3245
  /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
3221
3246
 
3222
3247
  "use strict";
3223
- __webpack_require__.r(__webpack_exports__);
3224
3248
  /* harmony import */ var _vandeurenglenn_base_x__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2353);
3225
3249
 
3226
3250
 
@@ -3228,7 +3252,7 @@ const base58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
3228
3252
 
3229
3253
  const decode = uint8Array => (0,_vandeurenglenn_base_x__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z)(base58).decode(uint8Array)
3230
3254
 
3231
- /* harmony default export */ __webpack_exports__["default"] = ({
3255
+ /* harmony default export */ __webpack_exports__["Z"] = ({
3232
3256
  encode: uint8Array => (0,_vandeurenglenn_base_x__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z)(base58).encode(uint8Array),
3233
3257
  decode,
3234
3258
  isBase58: uint8Array => {
@@ -3256,16 +3280,6 @@ globalThis.debug = text => {
3256
3280
  }
3257
3281
 
3258
3282
 
3259
- /***/ }),
3260
-
3261
- /***/ 6187:
3262
- /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
3263
-
3264
- "use strict";
3265
- __webpack_require__.r(__webpack_exports__);
3266
- /* harmony default export */ __webpack_exports__["default"] = (string => /^[A-F0-9]+$/i.test(string));
3267
-
3268
-
3269
3283
  /***/ }),
3270
3284
 
3271
3285
  /***/ 8162:
@@ -16966,11 +16980,11 @@ class MultiSignature {
16966
16980
  }
16967
16981
 
16968
16982
  export() {
16969
- return _vandeurenglenn_base58__WEBPACK_IMPORTED_MODULE_0__["default"].encode(this.multiSignature);
16983
+ return _vandeurenglenn_base58__WEBPACK_IMPORTED_MODULE_0__/* ["default"].encode */ .Z.encode(this.multiSignature);
16970
16984
  }
16971
16985
 
16972
16986
  import(encoded) {
16973
- return _vandeurenglenn_base58__WEBPACK_IMPORTED_MODULE_0__["default"].decode(this.decode(encoded));
16987
+ return _vandeurenglenn_base58__WEBPACK_IMPORTED_MODULE_0__/* ["default"].decode */ .Z.decode(this.decode(encoded));
16974
16988
  }
16975
16989
 
16976
16990
  sign(hash, privateKey) {
@@ -17047,23 +17061,23 @@ class MultiSignature {
17047
17061
  }
17048
17062
 
17049
17063
  fromHex(hex) {
17050
- return _vandeurenglenn_base58__WEBPACK_IMPORTED_MODULE_0__["default"].decode(Buffer.from(hex, 'hex'))
17064
+ return _vandeurenglenn_base58__WEBPACK_IMPORTED_MODULE_0__/* ["default"].decode */ .Z.decode(Buffer.from(hex, 'hex'))
17051
17065
  }
17052
17066
 
17053
17067
  toBs58() {
17054
- return _vandeurenglenn_base58__WEBPACK_IMPORTED_MODULE_0__["default"].encode(this.multiSignature)
17068
+ return _vandeurenglenn_base58__WEBPACK_IMPORTED_MODULE_0__/* ["default"].encode */ .Z.encode(this.multiSignature)
17055
17069
  }
17056
17070
 
17057
17071
  fromBs58(multiSignature) {
17058
- return _vandeurenglenn_base58__WEBPACK_IMPORTED_MODULE_0__["default"].decode(multiSignature)
17072
+ return _vandeurenglenn_base58__WEBPACK_IMPORTED_MODULE_0__/* ["default"].decode */ .Z.decode(multiSignature)
17059
17073
  }
17060
17074
 
17061
17075
  toBs32() {
17062
- return _vandeurenglenn_base32__WEBPACK_IMPORTED_MODULE_1__["default"].encode(this.multiSignature)
17076
+ return _vandeurenglenn_base32__WEBPACK_IMPORTED_MODULE_1__/* ["default"].encode */ .Z.encode(this.multiSignature)
17063
17077
  }
17064
17078
 
17065
17079
  fromBs32(multiSignature) {
17066
- return _vandeurenglenn_base32__WEBPACK_IMPORTED_MODULE_1__["default"].decode(multiSignature)
17080
+ return _vandeurenglenn_base32__WEBPACK_IMPORTED_MODULE_1__/* ["default"].decode */ .Z.decode(multiSignature)
17067
17081
  }
17068
17082
  }
17069
17083