@leofcoin/lib 0.4.13 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js DELETED
@@ -1,745 +0,0 @@
1
- 'use strict';
2
-
3
- var ipldLfcTx = require('ipld-lfc-tx');
4
- var ipldLfc = require('ipld-lfc');
5
- var CID = require('cids');
6
- var cryptoJs = require('crypto-js');
7
- var crypto = require('crypto');
8
- var MultiWallet = require('@leofcoin/multi-wallet');
9
-
10
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
11
-
12
- function _interopNamespace(e) {
13
- if (e && e.__esModule) return e;
14
- var n = Object.create(null);
15
- if (e) {
16
- Object.keys(e).forEach(function (k) {
17
- if (k !== 'default') {
18
- var d = Object.getOwnPropertyDescriptor(e, k);
19
- Object.defineProperty(n, k, d.get ? d : {
20
- enumerable: true,
21
- get: function () {
22
- return e[k];
23
- }
24
- });
25
- }
26
- });
27
- }
28
- n['default'] = e;
29
- return Object.freeze(n);
30
- }
31
-
32
- var ipldLfcTx__default = /*#__PURE__*/_interopDefaultLegacy(ipldLfcTx);
33
- var ipldLfcTx__namespace = /*#__PURE__*/_interopNamespace(ipldLfcTx);
34
- var ipldLfc__default = /*#__PURE__*/_interopDefaultLegacy(ipldLfc);
35
- var CID__default = /*#__PURE__*/_interopDefaultLegacy(CID);
36
- var cryptoJs__default = /*#__PURE__*/_interopDefaultLegacy(cryptoJs);
37
- var MultiWallet__default = /*#__PURE__*/_interopDefaultLegacy(MultiWallet);
38
-
39
- const reward = 150;
40
- const consensusSubsidyInterval = 52500;
41
- const genesisCID = 'zsNS6wZiHSc2QPHmjV8TMNn798b4Kp9jpjsBNeUkPhaJTza3GosWUgE72Jy3X9jKMrFCcDni7Pq4yXogQN4TcAfrPmTXFt';
42
- const GENESISBLOCK = {
43
- index: 0,
44
- prevHash: Buffer.alloc(47).toString('hex'),
45
- time: 1590240964,
46
- transactions: [],
47
- nonce: 1077701
48
- };
49
-
50
- /**
51
- * network (hardcoded for now)
52
- * @dev change to 'leofcoin:olivia' for testnet
53
- */
54
- const network = 'leofcoin';
55
-
56
- const invalid = (name, text) => new Error(`Invalid ${name}: ${text}`);
57
- // TODO: show notification
58
- /**
59
- * @example
60
- * const errors = new Errors()
61
- */
62
- class Errors {
63
- BlockError(text) {
64
- return invalid('block', text)
65
- }
66
-
67
- TransactionError(text) {
68
- return invalid('transaction', text)
69
- }
70
-
71
- MinerWarning(text) {
72
- }
73
- }
74
-
75
- const { LFCNode, util } = ipldLfc__default['default'];
76
- const {SHA256} = cryptoJs__default['default'];
77
-
78
- const _SHA256 = (object) => {
79
- return SHA256(JSON.stringify(object)).toString();
80
- };
81
-
82
- /**
83
- * @extends {Validator}
84
- * @example
85
- * const hash = new Hash()
86
- */
87
- class Hash extends Errors {
88
- constructor() {
89
- super();
90
- }
91
-
92
- hashFromMultihash(multihash) {
93
- const cid = new CID__default['default'](multihash.replace('/ipfs/', ''));
94
- return cid.multihash.slice(cid.prefix.length / 2).toString('hex')
95
- }
96
-
97
- multihashFromHash(hash) {
98
- const cid = new CID__default['default'](1, 'leofcoin-block', Buffer.from(`1d40${hash}`, 'hex'), 'base58btc');
99
- return cid.toBaseEncodedString();
100
- }
101
-
102
- async blockHash(block) {
103
- const cid = await util.cid(await util.serialize(await new LFCNode({...block})));
104
- return cid.toBaseEncodedString();
105
- }
106
-
107
- /**
108
- * Generate transaction hash
109
- *
110
- * @param {object} transaction {id, type, inputs, outputs}
111
- */
112
- async transactionHash(transaction) {
113
- const tx = await new ipldLfcTx__default['default'].LFCTx(transaction);
114
- const cid = await ipldLfcTx__default['default'].util.cid(await tx.serialize());
115
- return cid.toBaseEncodedString()
116
- }
117
-
118
- /**
119
- * Generate transaction input hash
120
- *
121
- * @param {object} transactionInput {transaction, index, amount, address}
122
- */
123
- transactionInputHash(transactionInput) {
124
- const {tx, index, amount, address} = transactionInput;
125
- return _SHA256({tx, index, amount, address});
126
- }
127
-
128
- }
129
-
130
- const { LFCTx, util: util$1 } = ipldLfcTx__namespace;
131
-
132
- /**
133
- * @extends {Hash}
134
- * @example
135
- * const transaction = new Transaction()
136
- */
137
- class Transaction extends Hash {
138
- constructor() {
139
- super();
140
- }
141
-
142
-
143
- /**
144
- * Create transaction
145
- *
146
- * @param inputs
147
- * @param outputs
148
- * @param reward
149
- * @return {{id: string, reward: boolean, inputs: *, outputs: *, hash: string}}
150
- */
151
- async newTransaction(inputs, outputs, reward = null) {
152
- try {
153
- const tx = new LFCTx({
154
- id: crypto.randomBytes(32).toString('hex'),
155
- time: Math.floor(new Date().getTime() / 1000),
156
- reward,
157
- outputs,
158
- inputs
159
- });
160
- // const cid = await util.cid(tx.serialize())
161
- // await global.ipfs.dag.put(tx, {format: util.codec, hashAlg: util.defaultHashAlg, version: 1, baseFormat: 'base58btc'})
162
- return tx
163
- } catch (e) {
164
- throw e
165
- }
166
- }
167
-
168
- /**
169
- * Create reward transaction for block mining
170
- *
171
- * @param {string} address
172
- * @param {number} height
173
- * @return {id: string, reward: boolean, inputs: *, outputs: *, hash: string}
174
- */
175
- async createRewardTransaction(address, amount) {
176
- return this.newTransaction([], [{index: 0, amount, address}], 'mined');
177
- }
178
-
179
- /**
180
- * validate transaction
181
- *
182
- * @param multihash
183
- * @param transaction
184
- * @param unspent
185
- */
186
- async validateTransaction(multihash, transaction, unspent) {
187
- if (!transaction.reward) delete transaction.reward;
188
- const outputs = transaction.outputs.map(o => {
189
- // TODO: fix script
190
- if (!o.script) delete o.script;
191
- return o
192
- });
193
- console.log(transaction);
194
- transaction.outputs = outputs;
195
- if (!transaction.script) delete transaction.script;
196
- if (!ipldLfcTx.util.isValid(transaction)) return await ipldLfcTx.util.validate(transaction)
197
- if (multihash !== await this.transactionHash(transaction)) throw this.TransactionError('Invalid transaction hash');
198
- // TODO: versions should be handled here...
199
- // Verify each input signature
200
-
201
- if (transaction.inputs) {
202
- transaction.inputs.forEach(input => {
203
- const { signature, address } = input;
204
- const hash = this.transactionInputHash(input);
205
-
206
- let wallet = new MultiWallet__default['default'](network);
207
- wallet.fromAddress(address, null, network);
208
-
209
- if (!wallet.verify(Buffer.from(signature, 'hex'), Buffer.from(hash, 'hex')))
210
- throw this.TransactionError('Invalid input signature');
211
- });
212
-
213
- // Check if inputs are in unspent list
214
- transaction.inputs.forEach((input) => {
215
- if (!unspent.find(out => out.tx === input.tx && out.index === input.index)) { throw this.TransactionError('Input has been already spent: ' + input.tx); }
216
- });
217
- }
218
-
219
- if (transaction.reward === 'mined') {
220
- // For reward transaction: check if reward output is correct
221
- if (transaction.outputs.length !== 1) throw this.TransactionError('Reward transaction must have exactly one output');
222
- if (transaction.outputs[0].amount !== reward) throw this.TransactionError(`Mining reward must be exactly: ${reward}`);
223
- } else if (transaction.inputs) {
224
- // For normal transaction: check if total output amount equals input amount
225
- if (transaction.inputs.reduce((acc, input) => acc + input.amount, 0) !==
226
- transaction.outputs.reduce((acc, output) => acc + output.amount, 0)) { throw this.TransactionError('Input and output amounts do not match'); }
227
- }
228
-
229
- return true;
230
- }
231
-
232
- /**
233
- * validate transactions list for current block
234
- *
235
- * @param {array} transactions
236
- * @param unspent
237
- */
238
- async validateTransactions(transactions, unspent) {
239
- const _transactions = [];
240
- for (let tx of transactions) {
241
- let multihash = tx.multihash;
242
-
243
- if (multihash) tx = await leofcoin.api.transaction.get(multihash);
244
- else {
245
- tx = await new LFCTx({...tx});
246
- multihash = await util$1.cid(await tx.serialize());
247
- multihash = multihash.toBaseEncodedString();
248
- }
249
-
250
- _transactions.push({multihash, value: tx.toJSON()});
251
- }
252
-
253
- try {
254
- for (const {value, multihash} of _transactions) {
255
- // TODO: fix value.scrip
256
- await this.validateTransaction(multihash, value, unspent);
257
- }
258
- } catch (e) {
259
- throw e
260
- }
261
-
262
- if (_transactions.filter(({value}) => value.reward === 'mined').length !== 1)
263
- throw this.TransactionError('Transactions cannot have more than one reward');
264
-
265
- return true
266
- }
267
-
268
- /**
269
- * Verify signature
270
- *
271
- * @param {string} address - signer address
272
- * @param {string} signature - signature to verify
273
- * @param {string} hash - transaction hash
274
- */
275
- verifySignature(address, signature, hash) {
276
- const wallet = new MultiWallet__default['default'](network);
277
- return wallet.verify(signature, hash, address);
278
- }
279
-
280
- /**
281
- * Create and sign input
282
- *
283
- * @param transaction Based on transaction id
284
- * @param index Based on transaction output index
285
- * @param amount
286
- * @param wallet
287
- * @return {Object} {transaction, index, amount, address}
288
- */
289
- createInput(transaction, index, amount, wallet) {
290
- const input = {
291
- tx: transaction,
292
- index,
293
- amount,
294
- address: wallet.address,
295
- };
296
- input.signature = wallet.sign(Buffer.from(this.transactionInputHash(input), 'hex')).toString('hex');
297
- return input;
298
- }
299
-
300
- /**
301
- * Create a transaction
302
- *
303
- * @param wallet
304
- * @param toAddress
305
- * @param amount
306
- * @return {Object} {id, reward, inputs, outputs, hash,}
307
- */
308
- async buildTransaction(wallet, toAddress, amount, unspent) {
309
- let inputsAmount = 0;
310
- // const unspent = await this.getUnspentForAddress(wallet.address);
311
- const inputsRaw = unspent.filter(i => {
312
- const more = inputsAmount < amount;
313
- if (more) inputsAmount += i.amount;
314
- return more;
315
- });
316
- if (inputsAmount < amount) throw this.TransactionError('Not enough funds');
317
- // TODO: Add multiSigning
318
- const inputs = inputsRaw.map(i => this.createInput(i.tx, i.index, i.amount, wallet));
319
- // Send amount to destination address
320
- const outputs = [{index: 0, amount, address: toAddress}];
321
- // Send back change to my wallet
322
- if (inputsAmount - amount > 0) {
323
- outputs.push({index: 1, amount: inputsAmount - amount, address: wallet.address});
324
- }
325
- return this.newTransaction(inputs, outputs);
326
- }
327
- }
328
-
329
- const { LFCNode: LFCNode$1, util: util$2 } = ipldLfc__default['default'];
330
-
331
-
332
- /**
333
- * @extends {Transaction}
334
- * @example
335
- * const block = new Block()
336
- */
337
- class Block extends Transaction {
338
- constructor() {
339
- super();
340
- }
341
-
342
- getDifficulty(hash) {
343
- return parseInt(hash.substring(0, 8), 16);
344
- }
345
-
346
- goodBlock(block, difficulty){
347
- return new Promise(async (resolve, reject) => {
348
- block.hash = await this.blockHash(block);
349
- if (parseInt(block.hash.substring(0, 8), 16) >= difficulty) {
350
- block.nonce++;
351
- block = await this.goodBlock(block, difficulty);
352
- }
353
- resolve(block);
354
- })
355
- }
356
-
357
- async validateBlock(previousBlock, block, difficulty, unspent) {
358
- const valid = await ipldLfc__default['default'].util.isValid(block);
359
- if (!valid) return await ipldLfc__default['default'].util.validate(block)
360
- // console.log(block, previousBlock);
361
- if (previousBlock.index + 1 !== block.index) return this.BlockError('index');
362
- if (!previousBlock.hash) {
363
- previousBlock = await new LFCNode$1(previousBlock);
364
- previousBlock = previousBlock.toJSON();
365
- previousBlock.hash = await util$2.cid(util$2.serialize(previousBlock));
366
- previousBlock.hash = previousBlock.hash.toBaseEncodedString();
367
- }
368
- console.log(await this.blockHash(block), block.hash);
369
- if (previousBlock.hash !== block.prevHash) throw this.BlockError('prevhash');
370
- if (await this.blockHash(block) !== block.hash) return this.BlockError('hash');
371
- if (this.getDifficulty(block.hash) > difficulty) return this.BlockError('difficulty');
372
-
373
-
374
- return this.validateTransactions(block.transactions, unspent);
375
- }
376
-
377
- /**
378
- * Create a new genesis block
379
- */
380
- async newGenesisDAGNode(difficulty = 1, address = Buffer.alloc(32).toString('hex')) {
381
- let block = {
382
- index: 0,
383
- prevHash: Buffer.alloc(47).toString('hex'),
384
- time: Math.floor(new Date().getTime() / 1000),
385
- transactions: [
386
- // ms.unspent(network, [], wallet.account()).create(index: 0, amount: consensusSubsidy(0), address)
387
- ],
388
- nonce: 0
389
- };
390
- block.hash = await blockHash(block);
391
- block = await this.goodBlock(block, difficulty);
392
- const node = new LFCNode$1(block);
393
- return node;
394
- }
395
- }
396
-
397
- const invalidTransactions = {};
398
-
399
- globalThis.chain = globalThis.chain || [
400
- GENESISBLOCK
401
- ];
402
-
403
- globalThis.mempool = globalThis.mempool || [];
404
- globalThis.blockHashSet = globalThis.blockHashSet || [];
405
-
406
- const filterPeers = (peers, localPeer) => {
407
- const set = [];
408
- return peers.reduce((p, c) => {
409
- if (set.indexOf(c.peer) === -1 && c.peer !== localPeer) {
410
- set.push(c.peer);
411
- p.push(c);
412
- }
413
- return p
414
- }, [])
415
- };
416
-
417
- /**
418
- * @extends {Block}
419
- * @example
420
- * const chain = new Chain()
421
- */
422
- class Chain extends Block {
423
- constructor() {
424
- super();
425
- }
426
-
427
- get chain() { return globalThis.chain }
428
-
429
- get mempool() { return globalThis.mempool }
430
-
431
- get blockHashSet() { return globalThis.blockHashSet }
432
-
433
- // TODO: needs 3 nodes running
434
- invalidTransaction(data) {
435
- // console.log(data.data.toString());
436
- data = JSON.parse(data.data.toString());
437
- if (!invalidTransactions[data.tx]) invalidTransactions[data.tx] = 0;
438
- ++invalidTransactions[data.tx];
439
- const count = invalidTransactions[data.tx];
440
- if (count === 3) {
441
- const memIndex = mempool.indexOf(data);
442
- mempool.splice(memIndex, 1);
443
- delete invalidTransactions[data.tx];
444
- }
445
- }
446
-
447
- /**
448
- * @param {number} height
449
- */
450
- consensusSubsidy(height) {
451
- // console.log(height);
452
- const quarterlings = height / consensusSubsidyInterval;
453
- if (quarterlings >= 256) {
454
- return 0;
455
- }
456
- //subsidy is lowered by 12.5 %, approx every year
457
- const minus = quarterlings >= 1 ? (quarterlings * (reward / 256)) : 0;
458
- return reward - minus;
459
- }
460
-
461
- async getTransactions(withMempool = true, index = 0) {
462
- const _chain = [...chain];
463
- if (index === chain.length - 1) return []
464
- _chain.slice(index + 1, chain.length - 1);
465
- let transactions = _chain.reduce((transactions, block) => [ ...transactions, ...block.transactions], []);
466
- if (withMempool) transactions = transactions.concat(mempool);
467
- let _transactions = [];
468
- // TODO: deprecated, get/put should be handled in core
469
- for (const tx of transactions) {
470
- const {multihash} = tx;
471
- if (multihash) {
472
- let value;
473
- if (leofcoin.api.transaction) value = await leofcoin.api.transaction.get(multihash);
474
- _transactions.push(value);
475
- } else {
476
- _transactions.push(tx);
477
- }
478
-
479
- }
480
- return _transactions
481
- };
482
-
483
- async getTransactionsForAddress(address, index = 0) {
484
- const transactions = await this.getTransactions(false, index);
485
- return transactions.filter(tx => tx.inputs.find(i => i.address === address) ||
486
- tx.outputs.find(o => o.address === address));
487
- };
488
-
489
- /**
490
- *
491
- * @param {string} withMempool - with or without mempool inclusion
492
- * @param {number} index - block height to start from
493
- */
494
- async getUnspent(withMempool = false, index = 0) {
495
- const transactions = await this.getTransactions(withMempool, index);
496
- // Find all inputs with their tx ids
497
- const inputs = transactions.reduce((inputs, tx) => inputs.concat(tx.inputs), []);
498
-
499
- // Find all outputs with their tx ids
500
- const outputs = transactions.reduce((outputs, tx) =>
501
- outputs.concat(tx.outputs.map(output => Object.assign({}, output, {tx: tx.id}))), []);
502
-
503
- // Figure out which outputs are unspent
504
- const unspent = outputs.filter(output =>
505
- typeof inputs.find(input => input.tx === output.tx && input.index === output.index && input.amount === output.amount) === 'undefined');
506
- return unspent;
507
- }
508
-
509
- /**
510
- * @param {String} address - wallet address
511
- * @param {number} index - block height to start from
512
- */
513
- async getUnspentForAddress(address = null, index = 0) {
514
- const unspent = await this.getUnspent(true, index);
515
- return unspent.filter(u => u.address === address);
516
- }
517
-
518
- /**
519
- * @param {String} address - wallet address
520
- * @param {Number} index - Block index to get balance after
521
- */
522
- async getBalanceForAddress(address = null, index) {
523
- // debug(`Getting balance for ${address}`)
524
- const unspent = await this.getUnspentForAddress(address, index);
525
- const amount = unspent.reduce((acc, u) => acc + u.amount , 0);
526
- // debug(`Got ${amount} for ${address}`)
527
- return amount
528
- }
529
-
530
- /**
531
- * @deprecated Use getTransactionsForAddress(addr, index) instead
532
- *
533
- * @param {string} address - wallet address
534
- * @param {number} index - block height to start from
535
- *
536
- * @return {number} balance
537
- */
538
- async getBalanceForAddressAfter(address = null, index = 0) {
539
- // debug(`Getting balance for ${address} @${index}`)
540
- const unspent = await this.getUnspentForAddress(address, index);
541
- const amount = unspent.reduce((acc, u) => acc + u.amount , 0);
542
- // debug(`Got ${amount} for ${address} @${index}`)
543
- return amount
544
- }
545
-
546
- median(array) {
547
- array.sort((a,b) => a - b);
548
-
549
- var half = Math.floor(array.length / 2);
550
-
551
- if(array.length % 2)
552
- return array[half];
553
- else
554
- return (array[half - 1] + array[half]) / 2.0;
555
- }
556
-
557
- difficulty() {
558
- // TODO: lower difficulty when transactionpool contain more then 500 tx ?
559
- // TODO: raise difficulty when pool is empty
560
-
561
- // or
562
-
563
- // TODO: implement iTX (instant transaction)
564
- // iTX is handled by multiple peers, itx is chained together by their hashes
565
- // by handlng a tx as itx the block well be converted into a iRootBlock
566
- // this results into smaller chains (tangles, tails) which should improve
567
- // resolving transactions, wallet amounts etc ...
568
- const start = chain.length >= 128 ? (chain.length - 128) : 0;
569
- const blocks = chain.slice(start, (chain.length - 1)).reverse();
570
- const stamps = [];
571
- for (var i = 0; i < blocks.length; i++) {
572
- if (blocks[i + 1]) {
573
- stamps.push(blocks[i].time - blocks[i + 1].time);
574
- }
575
- }
576
- if (stamps.length === 0) {
577
- stamps.push(10);
578
- }
579
- let blocksMedian = this.median(stamps) || 10;
580
- const offset = blocksMedian / 10;
581
- // offset for quick recovery
582
- if (blocksMedian < 10) {
583
- blocksMedian -= (offset / 2);
584
- } else if (blocksMedian > 10) {
585
- blocksMedian += (offset * 2);
586
- }
587
- if (blocksMedian < 0) blocksMedian = -blocksMedian;
588
- console.log(`Average Block Time: ${blocksMedian}`);
589
- console.log(`Difficulty: ${10 / blocksMedian}`);
590
- return (10000 / (10 / blocksMedian));
591
- };//10000
592
-
593
-
594
- /**
595
- * Get the transactions for the next Block
596
- *
597
- * @return {object} transactions
598
- */
599
- async nextBlockTransactions() {
600
-
601
- try {
602
- const unspent = await this.getUnspent(false);
603
- return mempool.filter(async transaction => {
604
- const multihash = transaction.multihash;
605
- const value = await leofcoin.api.transaction.get(multihash);
606
- try {
607
- await this.validateTransaction(multihash, value.toJSON(), unspent);
608
- return value.toJSON()
609
- } catch (e) {
610
- globalThis.pubsub.publish('invalid-transaction', Buffer.from(JSON.stringify(transaction)));
611
- console.error(e);
612
- }
613
- });
614
- } catch (e) {
615
- throw new Error(e)
616
- }
617
- }
618
-
619
- longestChain() {
620
- return new Promise(async (resolve, reject) => {
621
- try {
622
- // TODO: peernet.id => peer.id
623
- let peers = await filterPeers([...peernet.peers], peernet.id);
624
- let set = [];
625
- const request = new globalThis.peernet.protos['peernet-request']({
626
- request: 'lastBlock'
627
- });
628
-
629
- for (const peer of peers) {
630
- const to = peernet._getPeerId(peer.id);
631
- if (to) {
632
- const node = await peernet.prepareMessage(to, request.encoded);
633
- let response = await peer.request(node.encoded);
634
- const proto = new globalThis.peernet.protos['peernet-message'](Buffer.from(response.data));
635
- response = new globalThis.peernet.protos['peernet-response'](Buffer.from(proto.decoded.data));
636
- const block = JSON.parse(response.decoded.response);
637
- set.push({peer, block});
638
- }
639
- }
640
- let localIndex;
641
- let localHash;
642
- try {
643
- const index = await chainStore.get('localIndex');
644
- const hash = await chainStore.get('localBlock');
645
- localIndex = Number(index.toString());
646
- localHash = hash.toString();
647
- } catch (e) {
648
- localIndex = 0;
649
- localHash = genesisCID;
650
- await chainStore.put('localIndex', 0);
651
- await chainStore.put('localBlock', genesisCID);
652
- }
653
-
654
- set = set.reduce((p, c) => {
655
- if (Number(c.height) > Number(p.height)) {
656
- c.seen = 1;
657
- return c
658
- } else if (Number(c.height) === Number(p.height)) {
659
- p.seen += 1;
660
- }
661
- return p
662
- }, { height: localIndex, hash: localHash, seen: 0});
663
-
664
- // temp
665
- // if (_blocks.seen < 2) {
666
- // _blocks = history[_blocks.block.index - 1]
667
- //
668
- // }
669
- // const localIndex = await chainStore.get('localIndex')
670
- // const localHash = await chainStore.get('localBlock')
671
- return resolve({index: set.height, hash: set.hash})
672
-
673
- } catch (e) {
674
- console.warn(e);
675
- // debug(e)
676
- reject(e);
677
- }
678
- })
679
- }
680
-
681
- /**
682
- * Resolve latest block from the longest chain.
683
- * @return Promise(resolve(block))
684
- */
685
- lastBlock() {
686
- return new Promise(async (resolve, reject) => {
687
- const result = await this.longestChain();
688
-
689
- resolve(result); // retrieve links
690
- });
691
- }
692
-
693
- /**
694
- * @param {String} address
695
- * @return {Function} newBlock
696
- */
697
- async nextBlock(address) {
698
- let transactions;
699
- let previousBlock;
700
- try {
701
- previousBlock = await this.lastBlock();
702
-
703
- if (previousBlock.index > chain.length - 1) {
704
- await leofcoin.api.chain.sync();
705
- previousBlock = await this.lastBlock();
706
- }
707
- if (!previousBlock.index) previousBlock = chain[chain.length - 1];
708
- transactions = await this.nextBlockTransactions();
709
- } catch (e) {
710
- previousBlock = GENESISBLOCK;
711
- previousBlock.hash = genesisCID;
712
- transactions = await this.nextBlockTransactions();
713
- } finally {
714
- // console.log(transactions, previousBlock, address);
715
- return await this.newBlock({transactions, previousBlock, address});
716
- }
717
- }
718
-
719
- /**
720
- * Create new block
721
- *
722
- * @param {Array} transactions - transactions
723
- * @param {Object} previousBlock - previousBlock
724
- * @param {String} address - address
725
- * @return {Object} index, prevHash, time, transactions, nonce
726
- */
727
- async newBlock({transactions = [], previousBlock, address}) {
728
- const index = previousBlock.index + 1;
729
- const minedTx = await this.createRewardTransaction(address, this.consensusSubsidy(index));
730
- transactions.push(minedTx.toJSON());
731
- this.data = {
732
- index,
733
- prevHash: previousBlock.hash,
734
- time: Math.floor(new Date().getTime() / 1000),
735
- transactions,
736
- nonce: 0
737
- };
738
-
739
- this.data.hash = await this.blockHash({...this.data});
740
-
741
- return this.data;
742
- }
743
- }
744
-
745
- module.exports = Chain;