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