@leofcoin/peernet 0.11.14 → 0.11.15

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.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- /* socket-request-client version 1.6.1 */
3
+ /* socket-request-client version 1.6.3 */
4
4
 
5
5
  class LittlePubSub {
6
6
  constructor(verbose = true) {
@@ -187,9 +187,6 @@ const socketRequestClient = (url, protocols = 'echo-protocol', options = { retry
187
187
  peernet: api.peernet(client),
188
188
  server: api.server(client),
189
189
  close: exit => {
190
- client.onclose = message => {
191
- if (exit) process.exit();
192
- };
193
190
  client.close();
194
191
  }
195
192
  }
@@ -25,14 +25,14 @@ class FormatInterface {
25
25
  this.protoDecode = proto.decode;
26
26
  this.hashFormat = options.hashFormat || 'bs32';
27
27
  if (options.name) this.name = options.name;
28
- if (buffer instanceof Uint8Array) return this.fromUint8Array(buffer)
29
- else if (buffer instanceof ArrayBuffer) return this.fromArrayBuffer(buffer)
28
+ if (buffer instanceof Uint8Array) this.fromUint8Array(buffer);
29
+ else if (buffer instanceof ArrayBuffer) this.fromArrayBuffer(buffer);
30
30
  else if (buffer.name === options.name) return buffer
31
- else if (typeof buffer === 'string') {
32
- if (isHex__default["default"](buffer)) this.fromHex(buffer);
33
- else if (bs32__default["default"].isBase32(buffer)) this.fromBs32(buffer);
34
- else if (bs58__default["default"].isBase58(buffer)) this.fromBs58(buffer);
35
- else throw new Error(`unsupported string ${buffer}`)
31
+ else if (buffer instanceof String) {
32
+ if (isHex__default["default"](buffer)) this.fromHex(buffer);
33
+ else if (bs32__default["default"].isBase32(buffer)) this.fromBs32(buffer);
34
+ else if (bs58__default["default"].isBase58(buffer)) this.fromBs58(buffer);
35
+ else throw new Error(`unsupported string ${buffer}`)
36
36
  } else {
37
37
  this.create(buffer);
38
38
  }
@@ -10,7 +10,7 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
10
10
  var PubSub__default = /*#__PURE__*/_interopDefaultLegacy(PubSub);
11
11
  var Koa__default = /*#__PURE__*/_interopDefaultLegacy(Koa);
12
12
 
13
- var version = "0.11.13";
13
+ var version = "0.11.14";
14
14
 
15
15
  var api$1 = {
16
16
  version: ({send}) => send({client: '@peernet/api/http', version}),
@@ -14,16 +14,13 @@ var codec = require('./codec-45796010.js');
14
14
  var hash = require('./hash.js');
15
15
  var generateAccount = require('@leofcoin/generate-account');
16
16
  var bs58check = require('bs58check');
17
- var bip39 = require('bip39');
18
17
  var bip32 = require('bip32');
19
18
  var createKeccakHash = require('keccak');
20
- var secp256k1 = require('secp256k1');
21
19
  var ecc = require('tiny-secp256k1');
20
+ var Mnemonic = require('@leofcoin/mnemonic');
22
21
  var MultiSignature = require('multi-signature');
23
22
  var varint = require('varint');
24
- var AES = require('crypto-js/aes.js');
25
- require('crypto-js/sha512.js');
26
- var ENC = require('crypto-js/enc-utf8.js');
23
+ var randombytes = require('randombytes');
27
24
  require('@vandeurenglenn/base32');
28
25
  require('@vandeurenglenn/base58');
29
26
  require('@vandeurenglenn/is-hex');
@@ -57,12 +54,12 @@ var bs58check__namespace = /*#__PURE__*/_interopNamespace(bs58check);
57
54
  var bip32__namespace = /*#__PURE__*/_interopNamespace(bip32);
58
55
  var createKeccakHash__default = /*#__PURE__*/_interopDefaultLegacy(createKeccakHash);
59
56
  var ecc__default = /*#__PURE__*/_interopDefaultLegacy(ecc);
57
+ var Mnemonic__default = /*#__PURE__*/_interopDefaultLegacy(Mnemonic);
60
58
  var MultiSignature__default = /*#__PURE__*/_interopDefaultLegacy(MultiSignature);
61
59
  var varint__default = /*#__PURE__*/_interopDefaultLegacy(varint);
62
- var AES__default = /*#__PURE__*/_interopDefaultLegacy(AES);
63
- var ENC__default = /*#__PURE__*/_interopDefaultLegacy(ENC);
60
+ var randombytes__default = /*#__PURE__*/_interopDefaultLegacy(randombytes);
64
61
 
65
- /* socket-request-client version 1.6.1 */
62
+ /* socket-request-client version 1.6.3 */
66
63
 
67
64
  class LittlePubSub {
68
65
  constructor(verbose = true) {
@@ -249,9 +246,6 @@ const socketRequestClient = (url, protocols = 'echo-protocol', options = { retry
249
246
  peernet: api.peernet(client),
250
247
  server: api.server(client),
251
248
  close: exit => {
252
- client.onclose = message => {
253
- if (exit) process.exit();
254
- };
255
249
  client.close();
256
250
  }
257
251
  }
@@ -318,6 +312,10 @@ class Peer {
318
312
  return this.#connected
319
313
  }
320
314
 
315
+ get readyState() {
316
+ return this.channel?.readyState
317
+ }
318
+
321
319
  /**
322
320
  * @params {Object} options
323
321
  * @params {string} options.channelName - this peerid : otherpeer id
@@ -357,8 +355,19 @@ constructor(options = {}) {
357
355
  }
358
356
 
359
357
  send(message) {
360
- this.bw.up += message.length || message.byteLength;
361
- this.channel.send(message);
358
+ switch (this.channel?.readyState) {
359
+ case 'open':
360
+ this.bw.up += message.length || message.byteLength;
361
+ this.channel.send(message);
362
+ break;
363
+ case 'closed':
364
+ case 'closing':
365
+ debug('channel already closed, this usually means a bad implementation, try checking the readyState or check if the peer is connected before sending');
366
+ break;
367
+ case undefined:
368
+ debug(`trying to send before a channel is created`);
369
+ break;
370
+ }
362
371
  }
363
372
 
364
373
  request(data) {
@@ -431,7 +440,6 @@ constructor(options = {}) {
431
440
  this.channel.onmessage = (message) => {
432
441
  pubsub.publish('peer:data', message);
433
442
  debug(`incoming message from ${this.peerId}`);
434
- debug(message);
435
443
  this.bw.down += message.length || message.byteLength;
436
444
  };
437
445
 
@@ -491,6 +499,7 @@ constructor(options = {}) {
491
499
 
492
500
  close() {
493
501
  debug(`closing ${this.peerId}`);
502
+ this.#connected = false;
494
503
  this.channel?.close();
495
504
  this.#connection?.close();
496
505
 
@@ -507,6 +516,10 @@ class Client {
507
516
  return { ...this.#connections }
508
517
  }
509
518
 
519
+ get peers() {
520
+ return Object.entries(this.#connections)
521
+ }
522
+
510
523
  constructor(id, identifiers = ['peernet-v0.1.0'], stars = []) {
511
524
  this.id = id || Math.random().toString(36).slice(-12);
512
525
  if (!Array.isArray(identifiers)) identifiers = [identifiers];
@@ -621,6 +634,15 @@ class Client {
621
634
  debug(`peer ${id} joined`);
622
635
  }
623
636
 
637
+ removePeer(peer) {
638
+ const id = peer.peerId || peer;
639
+ if (this.#connections[id]) {
640
+ this.#connections[id].connected && this.#connections[id].close();
641
+ delete this.#connections[id];
642
+ }
643
+ debug(`peer ${id} removed`);
644
+ }
645
+
624
646
 
625
647
  }
626
648
 
@@ -1080,6 +1102,7 @@ const bitcoin = {
1080
1102
  messagePrefix: '\x18Bitcoin Signed Message:\n',
1081
1103
  bech32: 'bc',
1082
1104
  pubKeyHash: 0x00,
1105
+ multiCodec: 0x00,
1083
1106
  scriptHash: 0x05,
1084
1107
  wif: 0x80,
1085
1108
  coin_type: 0,
@@ -1128,12 +1151,15 @@ const fromNetworkString = network => {
1128
1151
  network = networks[parts[0]];
1129
1152
  if (parts[1]) {
1130
1153
  if (network[parts[1]]) network = network[parts[1]];
1131
-
1154
+
1132
1155
  network.coin_type = 1;
1133
1156
  }
1134
1157
  return network;
1135
1158
  };
1136
1159
 
1160
+ // import { createHash } from 'crypto'
1161
+ // import { createHash as _createHash } from './hash'
1162
+
1137
1163
  const { encode: encode$1, decode: decode$1 } = bs58check__default["default"];
1138
1164
  class HDWallet {
1139
1165
 
@@ -1161,20 +1187,48 @@ class HDWallet {
1161
1187
  return this.ifNotLocked(() => this.publicKeyBuffer.toString('hex'))
1162
1188
  }
1163
1189
 
1190
+ get ethereumAddress() {
1191
+ const buffer = ecc__default["default"].pointFromScalar(this.hdnode.__D, false);
1192
+ let hash = createKeccakHash__default["default"]('keccak256').update(buffer.slice(1)).digest();
1193
+ return `0x${hash.slice(-20).toString('hex')}`
1194
+ }
1195
+
1196
+ // async bitcoinAddress() {
1197
+ // const chainCode = this.privateKeyBuffer
1198
+ //
1199
+ // const node = bip32.fromPrivateKey(this.privateKeyBuffer, chainCode, networks['bitcoin'])
1200
+ // let buffer = await _createHash(node.publicKey, 'SHA-256')
1201
+ // buffer = createHash('ripemd160').update(buffer).digest()
1202
+ // // buffer = Buffer.from(`0x00${buffer.toString('hex')}`, 'hex')
1203
+ // // buffer = createHash('sha256').update(buffer).digest()
1204
+ // // const mainHash = buffer
1205
+ // // buffer = createHash('sha256').update(buffer).digest()
1206
+ // // const checksum = buffer.toString('hex').substring(0, 8)
1207
+ // // return base58.encode(Buffer.concat([mainHash, Buffer.from(checksum, 'hex')]))
1208
+ // const payload = Buffer.allocUnsafe(21)
1209
+ // payload.writeUInt8(networks['bitcoin'].pubKeyHash, 0)
1210
+ // buffer.copy(payload, 1)
1211
+ //
1212
+ // return encode(payload)
1213
+ // }
1214
+
1215
+ get leofcoinAddress() {
1216
+ return encode$1(this.neutered.publicKeyBuffer)
1217
+ }
1218
+
1164
1219
  get address() {
1165
- // override testnet coin_type
1166
- let coin_type = this.hdnode.network.coin_type;
1220
+ return this.getAddressForCoin()
1221
+ }
1222
+
1223
+ getAddressForCoin(coin_type) {
1224
+ if (!coin_type) coin_type = this.hdnode.network.coin_type;
1167
1225
  if (coin_type === 1) {
1168
1226
  if (this.networkName?.split(':')[0] === 'ethereum') coin_type = 60;
1169
1227
  if (this.networkName?.split(':')[0] === 'leofcoin') coin_type = 640;
1170
1228
  }
1171
- if (coin_type === 60 || coin_type === 640) {
1172
- let buffer = ecc__default["default"].pointFromScalar(this.hdnode.__D, false);
1173
- buffer = Buffer.from(secp256k1.publicKeyConvert(buffer, false)).slice(1);
1174
- let hash = createKeccakHash__default["default"]('keccak256').update(buffer).digest();
1175
- return hash.slice(-20).toString('hex')
1176
- }
1177
- return encode$1(this.neutered.publicKeyBuffer)
1229
+ // if (coin_type === 0) return this.bitcoinAddress
1230
+ if (coin_type === 60) return this.ethereumAddress
1231
+ if (coin_type === 640) return this.leofcoinAddress
1178
1232
  }
1179
1233
 
1180
1234
  get accountAddress() {
@@ -1221,10 +1275,10 @@ class HDWallet {
1221
1275
 
1222
1276
  async generate(password, network) {
1223
1277
  network = this.validateNetwork(network);
1224
- const mnemonic = bip39.generateMnemonic(256);
1225
- const seed = await bip39.mnemonicToSeed(mnemonic, password);
1278
+ const mnemonic = new Mnemonic__default["default"]().generate();
1279
+ const seed = new Mnemonic__default["default"]().seedFromMnemonic(mnemonic, password);
1226
1280
  this.defineHDNode(bip32__namespace.fromSeed(seed, network));
1227
- return mnemonic; // userpw
1281
+ return mnemonic;
1228
1282
  }
1229
1283
 
1230
1284
  /**
@@ -1232,7 +1286,7 @@ class HDWallet {
1232
1286
  */
1233
1287
  async recover(mnemonic, password, network) {
1234
1288
  network = this.validateNetwork(network, password);
1235
- const seed = await bip39.mnemonicToSeed(mnemonic);
1289
+ const seed = new Mnemonic__default["default"]().seedFromMnemonic(mnemonic, password);
1236
1290
  this.defineHDNode(bip32__namespace.fromSeed(seed, network));
1237
1291
  }
1238
1292
 
@@ -1265,6 +1319,71 @@ class HDWallet {
1265
1319
  }
1266
1320
  }
1267
1321
 
1322
+ const { subtle } = require('crypto').webcrypto;
1323
+
1324
+ const generateAesKey = async (length = 256) => {
1325
+ const key = await subtle.generateKey({
1326
+ name: 'AES-CBC',
1327
+ length
1328
+ }, true, ['encrypt', 'decrypt']);
1329
+
1330
+ return key;
1331
+ };
1332
+
1333
+ const importAesKey = async (exported, format = 'raw', length = 256) => {
1334
+ return await subtle.importKey(format, exported, {
1335
+ name: 'AES-CBC',
1336
+ length
1337
+ }, true, ['encrypt', 'decrypt'])
1338
+ };
1339
+
1340
+ const exportAesKey = async (key, format = 'raw') => {
1341
+ return await subtle.exportKey(format, key)
1342
+ };
1343
+
1344
+ const encryptAes = async (uint8Array, key, iv) => subtle.encrypt({
1345
+ name: 'AES-CBC',
1346
+ iv,
1347
+ }, key, uint8Array);
1348
+
1349
+ const uint8ArrayToHex = uint8Array =>
1350
+ [...uint8Array].map(x => x.toString(16).padStart(2, '0')).join('');
1351
+
1352
+ const arrayBufferToHex = arrayBuffer =>
1353
+ uint8ArrayToHex(new Uint8Array(arrayBuffer));
1354
+
1355
+ const hexToUint8Array = hex =>
1356
+ new Uint8Array(hex.match(/[\da-f]{2}/gi).map(x => parseInt(x, 16)));
1357
+
1358
+ const encrypt = async string => {
1359
+ const ec = new TextEncoder();
1360
+ const key = await generateAesKey();
1361
+ const iv = await randombytes__default["default"](16);
1362
+
1363
+ const ciphertext = await encryptAes(ec.encode(string), key, iv);
1364
+ const exported = await exportAesKey(key);
1365
+
1366
+ return {
1367
+ key: arrayBufferToHex(exported),
1368
+ iv: iv.toString('hex'),
1369
+ cipher: arrayBufferToHex(ciphertext)
1370
+ }
1371
+ };
1372
+
1373
+ const decrypt = async (cipher, key, iv) => {
1374
+ if (!key.type) key = await importAesKey(hexToUint8Array(key));
1375
+ cipher = new Uint8Array(hexToUint8Array(cipher));
1376
+ iv = new Uint8Array(hexToUint8Array(iv));
1377
+
1378
+ const dec = new TextDecoder();
1379
+ const plaintext = await subtle.decrypt({
1380
+ name: 'AES-CBC',
1381
+ iv,
1382
+ }, key, cipher);
1383
+
1384
+ return dec.decode(plaintext);
1385
+ };
1386
+
1268
1387
  const { encode, decode } = bs58check__namespace;
1269
1388
 
1270
1389
  // TODO: multihash addresses
@@ -1295,9 +1414,7 @@ class HDAccount {
1295
1414
 
1296
1415
  class MultiWallet extends HDWallet {
1297
1416
  constructor(network, hdnode) {
1298
- const networkName = network;
1299
1417
  super(network, hdnode);
1300
- if (typeof networkName === 'string') this.networkName = networkName;
1301
1418
  this.multiCodec = this.network.multiCodec;
1302
1419
  this.version = 0x00;
1303
1420
  }
@@ -1315,7 +1432,7 @@ class MultiWallet extends HDWallet {
1315
1432
  }
1316
1433
 
1317
1434
  get neutered() {
1318
- const neutered = this.ifNotLocked(() => new MultiWallet(this.network, this.hdnode.neutered()));
1435
+ const neutered = this.ifNotLocked(() => new MultiWallet(this.networkName, this.hdnode.neutered()));
1319
1436
  if (neutered) this._neutered = neutered;
1320
1437
  return this._neutered
1321
1438
  }
@@ -1324,18 +1441,19 @@ class MultiWallet extends HDWallet {
1324
1441
  let buffer = decode(id);
1325
1442
  varint__default["default"].decode(buffer);
1326
1443
  buffer = buffer.slice(varint__default["default"].decode.bytes);
1327
- this.fromPublicKey(buffer, null, this.network);
1444
+ this.fromPublicKey(buffer, null, this.networkName);
1328
1445
  }
1329
1446
 
1330
- lock(key, multiWIF) {
1447
+ async lock(multiWIF) {
1331
1448
  if (!multiWIF) multiWIF = this.multiWIF;
1332
- this.encrypted = AES__default["default"].encrypt(multiWIF.toString('hex'), key).toString();
1449
+ this.encrypted = await encrypt(multiWIF.toString('hex'));
1333
1450
  this.locked = true;
1451
+ return this.encrypted
1334
1452
  }
1335
1453
 
1336
- unlock(key, encrypted) {
1337
- if (!encrypted) encrypted = this.encrypted;
1338
- this.import(AES__default["default"].decrypt(encrypted, key).toString(ENC__default["default"]));
1454
+ async unlock({key, iv, cipher}) {
1455
+ const decrypted = await decrypt(cipher, key, iv);
1456
+ this.import(decrypted);
1339
1457
  this.locked = false;
1340
1458
  }
1341
1459
 
@@ -1355,7 +1473,7 @@ class MultiWallet extends HDWallet {
1355
1473
  else if (c.testnet && c.testnet.multiCodec === multiCodec) return c.testnet
1356
1474
  else return p
1357
1475
  }, networks['leofcoin']);
1358
- this.load(bs58, this.network);
1476
+ this.load(bs58, this.networkName);
1359
1477
  }
1360
1478
 
1361
1479
  /**
@@ -1398,7 +1516,7 @@ class MultiWallet extends HDWallet {
1398
1516
  * @return { internal(addressIndex), external(addressIndex) }
1399
1517
  */
1400
1518
  account(index) {
1401
- return new HDAccount(new MultiWallet(this.network, this.hdnode), index);
1519
+ return new HDAccount(new MultiWallet(this.networkName, this.hdnode), index);
1402
1520
  }
1403
1521
 
1404
1522
  /**
@@ -1407,11 +1525,11 @@ class MultiWallet extends HDWallet {
1407
1525
  * see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
1408
1526
  */
1409
1527
  derivePath(path) {
1410
- return new MultiWallet(this.network, this.hdnode.derivePath(path))
1528
+ return new MultiWallet(this.networkName, this.hdnode.derivePath(path))
1411
1529
  }
1412
1530
 
1413
1531
  derive(index) {
1414
- return new MultiWallet(this.network, this.hdnode.derive(index));
1532
+ return new MultiWallet(this.networkName, this.hdnode.derive(index));
1415
1533
  }
1416
1534
  }
1417
1535
 
@@ -1635,12 +1753,12 @@ class Peernet {
1635
1753
  this.hasDaemon = daemon;
1636
1754
 
1637
1755
  if (this.hasDaemon) {
1638
- const httpClient = await Promise.resolve().then(function () { return require('./client-1a1f75e6.js'); });
1756
+ const httpClient = await Promise.resolve().then(function () { return require('./client-5633ba04.js'); });
1639
1757
  globalThis.peernet.client = await httpClient.default({
1640
1758
  protocol: 'peernet-v0.1.0', host: '127.0.0.1', port: options.port
1641
1759
  });
1642
1760
  } else {
1643
- const http = await Promise.resolve().then(function () { return require('./http-68dd2b96.js'); });
1761
+ const http = await Promise.resolve().then(function () { return require('./http-f3ec9531.js'); });
1644
1762
  if (environment !== 'browser') http.default(options);
1645
1763
  }
1646
1764
 
@@ -1708,6 +1826,16 @@ class Peernet {
1708
1826
  this.requestProtos[name] = method;
1709
1827
  }
1710
1828
 
1829
+ sendMessage(peer, id, data) {
1830
+ if (peer.readyState === 'open') {
1831
+ peer.send(new TextEncoder().encode(JSON.stringify({id, data})));
1832
+ this.bw.up += data.length;
1833
+ } else if (peer.readyState === 'closed') {
1834
+ this.removePeer(peer);
1835
+ }
1836
+
1837
+ }
1838
+
1711
1839
  /**
1712
1840
  * @private
1713
1841
  *
@@ -1732,8 +1860,7 @@ class Peernet {
1732
1860
  const data = new dhtResponse({hash, has});
1733
1861
  const node = await this.prepareMessage(from, data.encoded);
1734
1862
 
1735
- peer.send(new TextEncoder().encode(JSON.stringify({id, data: node.encoded})));
1736
- this.bw.up += node.encoded.length;
1863
+ sendMessage(peer, id, node.encoded);
1737
1864
  } else if (proto.name === 'peernet-data') {
1738
1865
  let { hash, store } = proto.decoded;
1739
1866
  let data;
@@ -1746,24 +1873,19 @@ class Peernet {
1746
1873
  data = await store.get(hash);
1747
1874
 
1748
1875
  if (data) {
1749
- data = new DataMessageResponse({hash, data: data.decoded ? new TextEncoder().encode(JSON.stringify(data.decoded)) : data});
1876
+ data = new DataMessageResponse({hash, data});
1750
1877
 
1751
1878
  const node = await this.prepareMessage(from, data.encoded);
1752
- peer.send(new TextEncoder().encode(JSON.stringify({id, data: node.encoded})));
1753
- this.bw.up += node.encoded.length;
1879
+ sendMessage(peer, id, node.encoded);
1754
1880
  }
1755
1881
  }
1756
1882
 
1757
1883
  } else if (proto.name === 'peernet-request') {
1758
- // TODO: make dynamic
1759
- // exposeddevapi[proto.decoded.request](proto.decoded.params)
1760
1884
  const method = this.requestProtos[proto.decoded.request];
1761
1885
  if (method) {
1762
1886
  const data = await method();
1763
1887
  const node = await this.prepareMessage(from, data.encoded);
1764
- peer.send(new TextEncoder().encode(JSON.stringify({id, data: node.encoded})));
1765
-
1766
- this.bw.up += node.encoded.length;
1888
+ sendMessage(peer, id, node.encoded);
1767
1889
  }
1768
1890
  } else if (proto.name === 'peernet-ps' && peer.peerId !== this.id) {
1769
1891
  globalSub.publish(new TextDecoder().decode(proto.decoded.topic), proto.decoded.data);
@@ -2033,13 +2155,9 @@ class Peernet {
2033
2155
  const id = Math.random().toString(36).slice(-12);
2034
2156
  data = new PsMessage({data, topic});
2035
2157
  for (const peer of this.connections) {
2036
- if (peer.connected) {
2037
- if (peer.peerId !== this.peerId) {
2038
- const node = await this.prepareMessage(peer.peerId, data.encoded);
2039
- peer.send(new TextEncoder().encode(JSON.stringify({id, data: node.encoded})));
2040
- }
2041
- } else {
2042
- this.removePeer(peer);
2158
+ if (peer.peerId !== this.peerId) {
2159
+ const node = await this.prepareMessage(peer.peerId, data.encoded);
2160
+ sendMessage(peer, id, node.encoded);
2043
2161
  }
2044
2162
  // TODO: if peer subscribed
2045
2163
  }
@@ -2060,7 +2178,7 @@ class Peernet {
2060
2178
  }
2061
2179
 
2062
2180
  async removePeer(peer) {
2063
- delete this.client.connections[peer.peerId];
2181
+ return this.client.removePeer(peer)
2064
2182
  }
2065
2183
 
2066
2184
  get Buffer() {