DuniterBlockchain.ts 21.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
// Source file from duniter: Crypto-currency software to manage libre currency such as Ğ1
// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.

14
import {FullIindexEntry, IindexEntry, IndexEntry, Indexer, MindexEntry, SindexEntry} from "../indexer"
15
16
17
18
import {ConfDTO} from "../dto/ConfDTO"
import {BlockDTO} from "../dto/BlockDTO"
import {DBHead} from "../db/DBHead"
import {DBBlock} from "../db/DBBlock"
19
import {CHECK} from "../rules/index"
20
21
import {RevocationDTO} from "../dto/RevocationDTO"
import {IdentityDTO} from "../dto/IdentityDTO"
22
import {CertificationDTO} from "../dto/CertificationDTO"
23
import {MembershipDTO} from "../dto/MembershipDTO"
24
import {TransactionDTO} from "../dto/TransactionDTO"
25
import {CommonConstants} from "../common-libs/constants"
26
import {FileDAL} from "../dal/fileDAL"
27
import {DataErrors} from "../common-libs/errors"
Cédric Moreau's avatar
Cédric Moreau committed
28
import {NewLogger} from "../logger"
29
import {DBTx} from "../db/DBTx"
30
31
32

const _ = require('underscore')

Cédric Moreau's avatar
Cédric Moreau committed
33
export class DuniterBlockchain {
34

35
  static async checkBlock(block:BlockDTO, withPoWAndSignature:boolean, conf: ConfDTO, dal:FileDAL) {
36
    const index = Indexer.localIndex(block, conf)
37
    if (withPoWAndSignature) {
38
      await CHECK.ASYNC.ALL_LOCAL(block, conf, index)
39
40
    }
    else {
41
      await CHECK.ASYNC.ALL_LOCAL_BUT_POW(block, conf, index)
42
    }
43
    const HEAD = await Indexer.completeGlobalScope(block, conf, index, dal);
44
    const HEAD_1 = await dal.bindexDAL.head(1);
45
46
47
48
    const mindex = Indexer.mindex(index);
    const iindex = Indexer.iindex(index);
    const sindex = Indexer.sindex(index);
    const cindex = Indexer.cindex(index);
49
    // BR_G49
50
    if (Indexer.ruleVersion(HEAD, HEAD_1) === false) throw Error('ruleVersion');
51
    // BR_G50
52
    if (Indexer.ruleBlockSize(HEAD) === false) throw Error('ruleBlockSize');
53
    // BR_G98
54
    if (Indexer.ruleCurrency(block, HEAD) === false) throw Error('ruleCurrency');
55
    // BR_G51
Cédric Moreau's avatar
Cédric Moreau committed
56
57
58
    if (Indexer.ruleNumber(block, HEAD) === false) {
      throw Error('ruleNumber')
    }
59
    // BR_G52
60
    if (Indexer.rulePreviousHash(block, HEAD) === false) throw Error('rulePreviousHash');
61
    // BR_G53
62
    if (Indexer.rulePreviousIssuer(block, HEAD) === false) throw Error('rulePreviousIssuer');
63
    // BR_G101
64
    if (Indexer.ruleIssuerIsMember(HEAD) === false) throw Error('ruleIssuerIsMember');
65
    // BR_G54
66
    if (Indexer.ruleIssuersCount(block, HEAD) === false) throw Error('ruleIssuersCount');
67
    // BR_G55
68
    if (Indexer.ruleIssuersFrame(block, HEAD) === false) throw Error('ruleIssuersFrame');
69
    // BR_G56
70
    if (Indexer.ruleIssuersFrameVar(block, HEAD) === false) throw Error('ruleIssuersFrameVar');
71
    // BR_G57
72
73
74
    if (Indexer.ruleMedianTime(block, HEAD) === false) {
      throw Error('ruleMedianTime')
    }
75
    // BR_G58
76
    if (Indexer.ruleDividend(block, HEAD) === false) throw Error('ruleDividend');
77
    // BR_G59
78
    if (Indexer.ruleUnitBase(block, HEAD) === false) throw Error('ruleUnitBase');
79
    // BR_G60
80
    if (Indexer.ruleMembersCount(block, HEAD) === false) throw Error('ruleMembersCount');
81
    // BR_G61
82
    if (Indexer.rulePowMin(block, HEAD) === false) throw Error('rulePowMin');
83
84
    if (withPoWAndSignature) {
      // BR_G62
85
      if (Indexer.ruleProofOfWork(HEAD) === false) throw Error('ruleProofOfWork');
86
87
    }
    // BR_G63
88
    if (Indexer.ruleIdentityWritability(iindex, conf) === false) throw Error('ruleIdentityWritability');
89
    // BR_G64
90
    if (Indexer.ruleMembershipWritability(mindex, conf) === false) throw Error('ruleMembershipWritability');
91
    // BR_G108
92
    if (Indexer.ruleMembershipPeriod(mindex) === false) throw Error('ruleMembershipPeriod');
93
    // BR_G65
94
    if (Indexer.ruleCertificationWritability(cindex, conf) === false) throw Error('ruleCertificationWritability');
95
    // BR_G66
96
    if (Indexer.ruleCertificationStock(cindex, conf) === false) throw Error('ruleCertificationStock');
97
    // BR_G67
98
    if (Indexer.ruleCertificationPeriod(cindex) === false) throw Error('ruleCertificationPeriod');
99
    // BR_G68
100
    if (Indexer.ruleCertificationFromMember(HEAD, cindex) === false) throw Error('ruleCertificationFromMember');
101
    // BR_G69
102
    if (Indexer.ruleCertificationToMemberOrNewcomer(cindex) === false) throw Error('ruleCertificationToMemberOrNewcomer');
103
    // BR_G70
104
    if (Indexer.ruleCertificationToLeaver(cindex) === false) throw Error('ruleCertificationToLeaver');
105
    // BR_G71
Cédric Moreau's avatar
Cédric Moreau committed
106
107
108
    if (Indexer.ruleCertificationReplay(cindex) === false) {
      throw Error('ruleCertificationReplay')
    }
109
    // BR_G72
110
    if (Indexer.ruleCertificationSignature(cindex) === false) throw Error('ruleCertificationSignature');
111
    // BR_G73
112
    if (Indexer.ruleIdentityUIDUnicity(iindex) === false) throw Error('ruleIdentityUIDUnicity');
113
    // BR_G74
114
    if (Indexer.ruleIdentityPubkeyUnicity(iindex) === false) throw Error('ruleIdentityPubkeyUnicity');
115
    // BR_G75
116
    if (Indexer.ruleMembershipSuccession(mindex) === false) throw Error('ruleMembershipSuccession');
117
    // BR_G76
118
    if (Indexer.ruleMembershipDistance(HEAD, mindex) === false) throw Error('ruleMembershipDistance');
119
    // BR_G77
120
    if (Indexer.ruleMembershipOnRevoked(mindex) === false) throw Error('ruleMembershipOnRevoked');
121
    // BR_G78
122
    if (Indexer.ruleMembershipJoinsTwice(mindex) === false) throw Error('ruleMembershipJoinsTwice');
123
    // BR_G79
124
    if (Indexer.ruleMembershipEnoughCerts(mindex) === false) throw Error('ruleMembershipEnoughCerts');
125
    // BR_G80
126
    if (Indexer.ruleMembershipLeaverIsMember(mindex) === false) throw Error('ruleMembershipLeaverIsMember');
127
    // BR_G81
Cédric Moreau's avatar
Cédric Moreau committed
128
129
130
    if (Indexer.ruleMembershipActiveIsMember(mindex) === false) {
      throw Error('ruleMembershipActiveIsMember')
    }
131
    // BR_G82
132
    if (Indexer.ruleMembershipRevokedIsMember(mindex) === false) throw Error('ruleMembershipRevokedIsMember');
133
    // BR_G83
134
    if (Indexer.ruleMembershipRevokedSingleton(mindex) === false) throw Error('ruleMembershipRevokedSingleton');
135
    // BR_G84
136
    if (Indexer.ruleMembershipRevocationSignature(mindex) === false) throw Error('ruleMembershipRevocationSignature');
137
    // BR_G85
138
    if (Indexer.ruleMembershipExcludedIsMember(iindex) === false) throw Error('ruleMembershipExcludedIsMember');
139
    // BR_G86
Cédric Moreau's avatar
Cédric Moreau committed
140
141
142
    if ((await Indexer.ruleToBeKickedArePresent(iindex, dal)) === false) {
      throw Error('ruleToBeKickedArePresent')
    }
143
    // BR_G103
144
    if (Indexer.ruleTxWritability(sindex) === false) throw Error('ruleTxWritability');
145
    // BR_G87
146
    if (Indexer.ruleInputIsAvailable(sindex) === false) throw Error('ruleInputIsAvailable');
147
    // BR_G88
148
    if (Indexer.ruleInputIsUnlocked(sindex) === false) throw Error('ruleInputIsUnlocked');
149
    // BR_G89
150
    if (Indexer.ruleInputIsTimeUnlocked(sindex) === false) throw Error('ruleInputIsTimeUnlocked');
151
    // BR_G90
152
    if (Indexer.ruleOutputBase(sindex, HEAD_1) === false) throw Error('ruleOutputBase');
153
154
    // Check document's coherence

155
    const matchesList = (regexp:RegExp, list:string[]) => {
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
      let i = 0;
      let found = "";
      while (!found && i < list.length) {
        found = list[i].match(regexp) ? list[i] : "";
        i++;
      }
      return found;
    }

    const isMember = await dal.isMember(block.issuer);
    if (!isMember) {
      if (block.number == 0) {
        if (!matchesList(new RegExp('^' + block.issuer + ':'), block.joiners)) {
          throw Error('Block not signed by the root members');
        }
      } else {
        throw Error('Block must be signed by an existing member');
      }
    }

    // Generate the local index
    // Check the local rules
    // Enrich with the global index
    // Check the global rules
    return { index, HEAD }
  }

Cédric Moreau's avatar
Cédric Moreau committed
183
  static async pushTheBlock(obj:BlockDTO, index:IndexEntry[], HEAD:DBHead | null, conf:ConfDTO, dal:FileDAL, logger:any) {
184
    const start = Date.now();
185
    const block = BlockDTO.fromJSONObject(obj)
186
187
188
    try {
      const currentBlock = await dal.getCurrentBlockOrNull();
      block.fork = false;
189
      const added = await this.saveBlockData(currentBlock, block, conf, dal, logger, index, HEAD);
190
191
192
193
194
195
196
197

      try {
        await DuniterBlockchain.pushStatsForBlocks([block], dal);
      } catch (e) {
        logger.warn("An error occurred after the add of the block", e.stack || e);
      }

      logger.info('Block #' + block.number + ' added to the blockchain in %s ms', (Date.now() - start));
198
      return BlockDTO.fromJSONObject(added)
199
200
201
202
203
204
205
206
207
208
209
    }
    catch(err) {
      throw err;
    }

    // Enrich the index with post-HEAD indexes
    // Push the block into the blockchain
    // await supra.pushBlock(b)
    // await supra.recordIndex(index)
  }

Cédric Moreau's avatar
Cédric Moreau committed
210
  static async saveBlockData(current:DBBlock|null, block:BlockDTO, conf:ConfDTO, dal:FileDAL, logger:any, index:IndexEntry[], HEAD:DBHead | null) {
211
212
213
214
215
216
217
218
219
220
    if (block.number == 0) {
      await this.saveParametersForRoot(block, conf, dal);
    }

    const indexes = await dal.generateIndexes(block, conf, index, HEAD);

    // Newcomers
    await this.createNewcomers(indexes.iindex, dal, logger);

    // Save indexes
Cédric Moreau's avatar
Cédric Moreau committed
221
    await dal.bindexDAL.insert(indexes.HEAD);
222
223
224
225
226
227
228
229
230
231
232
233
234
    await dal.mindexDAL.insertBatch(indexes.mindex);
    await dal.iindexDAL.insertBatch(indexes.iindex);
    await dal.sindexDAL.insertBatch(indexes.sindex);
    await dal.cindexDAL.insertBatch(indexes.cindex);

    // Create/Update nodes in wotb
    await this.updateMembers(block, dal);

    // Update the wallets' blances
    await this.updateWallets(indexes.sindex, dal)

    const TAIL = await dal.bindexDAL.tail();
    const bindexSize = [
235
236
      TAIL.issuersCount,
      TAIL.issuersFrame,
237
238
239
240
241
      conf.medianTimeBlocks,
      conf.dtDiffEval
    ].reduce((max, value) => {
      return Math.max(max, value);
    }, 0);
242
243
    const MAX_BINDEX_SIZE = conf.forksize + bindexSize
    const currentSize = indexes.HEAD.number - TAIL.number + 1
244
245
246
247
    if (currentSize > MAX_BINDEX_SIZE) {
      await dal.trimIndexes(indexes.HEAD.number - MAX_BINDEX_SIZE);
    }

248
    const dbb = DBBlock.fromBlockDTO(block)
249
    this.updateBlocksComputedVars(current, dbb)
250
251
252
253
254

    // --> Update links
    await dal.updateWotbLinks(indexes.cindex);

    // Create/Update certifications
255
    await DuniterBlockchain.removeCertificationsFromSandbox(block, dal);
256
257
258
259
260
261
262
263
    // Create/Update memberships
    await this.removeMembershipsFromSandbox(block, dal);
    // Compute to be revoked members
    await this.computeToBeRevoked(indexes.mindex, dal);
    // Delete eventually present transactions
    await this.deleteTransactions(block, dal);

    await dal.trimSandboxes(block);
264
265
    // Saves the block (DAL)
    await dal.saveBlock(dbb);
266

267
268
    await dal.loki.commitData()

269
    return dbb
270
271
  }

Cédric Moreau's avatar
Cédric Moreau committed
272
  static async saveParametersForRoot(block:BlockDTO, conf:ConfDTO, dal:FileDAL) {
273
    if (block.parameters) {
274
      const bconf = BlockDTO.getConf(block)
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
      conf.c = bconf.c;
      conf.dt = bconf.dt;
      conf.ud0 = bconf.ud0;
      conf.sigPeriod = bconf.sigPeriod;
      conf.sigStock = bconf.sigStock;
      conf.sigWindow = bconf.sigWindow;
      conf.sigValidity = bconf.sigValidity;
      conf.sigQty = bconf.sigQty;
      conf.idtyWindow = bconf.idtyWindow;
      conf.msWindow = bconf.msWindow;
      conf.xpercent = bconf.xpercent;
      conf.msValidity = bconf.msValidity;
      conf.stepMax = bconf.stepMax;
      conf.medianTimeBlocks = bconf.medianTimeBlocks;
      conf.avgGenTime = bconf.avgGenTime;
      conf.dtDiffEval = bconf.dtDiffEval;
      conf.percentRot = bconf.percentRot;
      conf.udTime0 = bconf.udTime0;
      conf.udReevalTime0 = bconf.udReevalTime0;
      conf.dtReeval = bconf.dtReeval;
295
      conf.currency = bconf.currency;
296
297
298
299
300
301
      // Super important: adapt wotb module to handle the correct stock
      dal.wotb.setMaxCert(conf.sigStock);
      return dal.saveConf(conf);
    }
  }

Cédric Moreau's avatar
Cédric Moreau committed
302
  static async createNewcomers(iindex:IindexEntry[], dal:FileDAL, logger:any) {
303
304
305
    for (const i of iindex) {
      if (i.op == CommonConstants.IDX_CREATE) {
        const entry = i as FullIindexEntry
306
307
308
309
        // Reserves a wotb ID
        entry.wotb_id = dal.wotb.addNode();
        logger.trace('%s was affected wotb_id %s', entry.uid, entry.wotb_id);
        // Remove from the sandbox any other identity with the same pubkey/uid, since it has now been reserved.
310
311
        await dal.removeUnWrittenWithPubkey(entry.pub)
        await dal.removeUnWrittenWithUID(entry.uid)
312
313
314
315
      }
    }
  }

Cédric Moreau's avatar
Cédric Moreau committed
316
  static async updateMembers(block:BlockDTO, dal:FileDAL) {
317
318
    // Joiners (come back)
    for (const inlineMS of block.joiners) {
319
      let ms = MembershipDTO.fromInline(inlineMS)
320
      const idty = await dal.getWrittenIdtyByPubkeyForWotbID(ms.issuer);
321
322
323
324
      dal.wotb.setEnabled(true, idty.wotb_id);
    }
    // Revoked
    for (const inlineRevocation of block.revoked) {
325
      let revocation = RevocationDTO.fromInline(inlineRevocation)
326
      await dal.revokeIdentity(revocation.pubkey)
327
328
329
    }
    // Excluded
    for (const excluded of block.excluded) {
330
      const idty = await dal.getWrittenIdtyByPubkeyForWotbID(excluded);
331
332
333
334
      dal.wotb.setEnabled(false, idty.wotb_id);
    }
  }

Cédric Moreau's avatar
Cédric Moreau committed
335
  static async updateWallets(sindex:SindexEntry[], aDal:any, reverse = false) {
336
337
    const differentConditions = _.uniq(sindex.map((entry) => entry.conditions))
    for (const conditions of differentConditions) {
338
339
      const creates = _.filter(sindex, (entry:SindexEntry) => entry.conditions === conditions && entry.op === CommonConstants.IDX_CREATE)
      const updates = _.filter(sindex, (entry:SindexEntry) => entry.conditions === conditions && entry.op === CommonConstants.IDX_UPDATE)
340
341
      const positives = creates.reduce((sum:number, src:SindexEntry) => sum + src.amount * Math.pow(10, src.base), 0)
      const negatives = updates.reduce((sum:number, src:SindexEntry) => sum + src.amount * Math.pow(10, src.base), 0)
342
343
344
345
346
347
348
349
350
351
352
      const wallet = await aDal.getWallet(conditions)
      let variation = positives - negatives
      if (reverse) {
        // To do the opposite operations, for a reverted block
        variation *= -1
      }
      wallet.balance += variation
      await aDal.saveWallet(wallet)
    }
  }

Cédric Moreau's avatar
Cédric Moreau committed
353
  static async revertBlock(number:number, hash:string, dal:FileDAL) {
354
355

    const blockstamp = [number, hash].join('-');
356
357
358
359
360
    const block = await dal.getBlockByBlockstampOrNull(blockstamp)

    if (!block) {
      throw DataErrors[DataErrors.BLOCK_TO_REVERT_NOT_FOUND]
    }
361
362
363
364

    // Revert links
    const writtenOn = await dal.cindexDAL.getWrittenOn(blockstamp);
    for (const entry of writtenOn) {
365
366
      const from = await dal.getWrittenIdtyByPubkeyForWotbID(entry.issuer);
      const to = await dal.getWrittenIdtyByPubkeyForWotbID(entry.receiver);
367
      if (entry.op == CommonConstants.IDX_CREATE) {
368
        // We remove the created link
369
        dal.wotb.removeLink(from.wotb_id, to.wotb_id);
370
371
      } else {
        // We add the removed link
372
        dal.wotb.addLink(from.wotb_id, to.wotb_id);
373
374
375
376
377
378
379
380
381
382
      }
    }

    // Revert nodes
    await this.undoMembersUpdate(blockstamp, dal);

    // Get the money movements to revert in the balance
    const REVERSE_BALANCE = true
    const sindexOfBlock = await dal.sindexDAL.getWrittenOn(blockstamp)

Cédric Moreau's avatar
Cédric Moreau committed
383
    await dal.bindexDAL.removeBlock(blockstamp);
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
    await dal.mindexDAL.removeBlock(blockstamp);
    await dal.iindexDAL.removeBlock(blockstamp);
    await dal.cindexDAL.removeBlock(blockstamp);
    await dal.sindexDAL.removeBlock(blockstamp);

    // Then: normal updates
    const previousBlock = await dal.getBlock(number - 1);
    // Set the block as SIDE block (equivalent to removal from main branch)
    await dal.blockDAL.setSideBlock(number, previousBlock);

    // Revert the balances variations for this block
    await this.updateWallets(sindexOfBlock, dal, REVERSE_BALANCE)

    // Restore block's transaction as incoming transactions
    await this.undoDeleteTransactions(block, dal)
399
400

    return block
401
402
  }

Cédric Moreau's avatar
Cédric Moreau committed
403
  static async undoMembersUpdate(blockstamp:string, dal:FileDAL) {
404
405
406
407
    const joiners = await dal.iindexDAL.getWrittenOn(blockstamp);
    for (const entry of joiners) {
      // Undo 'join' which can be either newcomers or comebackers
      // => equivalent to i_index.member = true AND i_index.op = 'UPDATE'
408
      if (entry.member === true && entry.op === CommonConstants.IDX_UPDATE) {
409
        const idty = await dal.getWrittenIdtyByPubkeyForWotbID(entry.pub);
410
411
412
413
414
415
416
        dal.wotb.setEnabled(false, idty.wotb_id);
      }
    }
    const newcomers = await dal.iindexDAL.getWrittenOn(blockstamp);
    for (const entry of newcomers) {
      // Undo newcomers
      // => equivalent to i_index.op = 'CREATE'
417
      if (entry.op === CommonConstants.IDX_CREATE) {
418
        // Does not matter which one it really was, we pop the last X identities
Cédric Moreau's avatar
Cédric Moreau committed
419
        NewLogger().trace('removeNode')
420
421
422
423
424
425
426
        dal.wotb.removeNode();
      }
    }
    const excluded = await dal.iindexDAL.getWrittenOn(blockstamp);
    for (const entry of excluded) {
      // Undo excluded (make them become members again in wotb)
      // => equivalent to m_index.member = false
427
      if (entry.member === false && entry.op === CommonConstants.IDX_UPDATE) {
428
        const idty = await dal.getWrittenIdtyByPubkeyForWotbID(entry.pub);
429
430
431
432
433
        dal.wotb.setEnabled(true, idty.wotb_id);
      }
    }
  }

Cédric Moreau's avatar
Cédric Moreau committed
434
  static async undoDeleteTransactions(block:DBBlock, dal:FileDAL) {
435
436
    for (const obj of block.transactions) {
      obj.currency = block.currency;
437
      let tx = TransactionDTO.fromJSONObject(obj)
438
      await dal.saveTransaction(DBTx.fromTransactionDTO(tx))
439
440
441
442
443
444
445
446
447
    }
  }

  /**
   * Delete certifications from the sandbox since it has been written.
   *
   * @param block Block in which are contained the certifications to remove from sandbox.
   * @param dal The DAL
   */
448
  static async removeCertificationsFromSandbox(block:BlockDTO, dal:FileDAL) {
449
    for (let inlineCert of block.certifications) {
450
      let cert = CertificationDTO.fromInline(inlineCert)
451
      let idty = await dal.getWrittenIdtyByPubkeyForHashing(cert.to);
452
453
454
455
456
      await dal.deleteCert({
        from: cert.from,
        target: IdentityDTO.getTargetHash(idty),
        sig: cert.sig,
      });
457
458
459
460
461
462
463
464
465
    }
  }

  /**
   * Delete memberships from the sandbox since it has been written.
   *
   * @param block Block in which are contained the certifications to remove from sandbox.
   * @param dal The DAL
   */
Cédric Moreau's avatar
Cédric Moreau committed
466
  static async removeMembershipsFromSandbox(block:BlockDTO, dal:FileDAL) {
467
468
    const mss = block.joiners.concat(block.actives).concat(block.leavers);
    for (const inlineMS of mss) {
469
470
471
472
473
      let ms = MembershipDTO.fromInline(inlineMS)
      await dal.deleteMS({
        issuer: ms.issuer,
        signature: ms.signature
      });
474
475
476
    }
  }

Cédric Moreau's avatar
Cédric Moreau committed
477
  static async computeToBeRevoked(mindex:MindexEntry[], dal:FileDAL) {
478
    const revocations = _.filter(mindex, (entry:MindexEntry) => entry.revoked_on);
479
    for (const revoked of revocations) {
480
      await dal.setRevoked(revoked.pub)
481
482
483
    }
  }

Cédric Moreau's avatar
Cédric Moreau committed
484
  static async deleteTransactions(block:BlockDTO, dal:FileDAL) {
485
486
    for (const obj of block.transactions) {
      obj.currency = block.currency;
487
      const tx = TransactionDTO.fromJSONObject(obj)
488
489
490
491
492
      const txHash = tx.getHash();
      await dal.removeTxByHash(txHash);
    }
  }

Cédric Moreau's avatar
Cédric Moreau committed
493
  static updateBlocksComputedVars(
494
495
    current:{ unitbase:number, monetaryMass:number }|null,
    block:{ number:number, unitbase:number, dividend:number|null, membersCount:number, monetaryMass:number }): void {
496
497
498
499
500
501
    // Unit Base
    block.unitbase = (block.dividend && block.unitbase) || (current && current.unitbase) || 0;
    // Monetary Mass update
    if (current) {
      block.monetaryMass = (current.monetaryMass || 0)
        + (block.dividend || 0) * Math.pow(10, block.unitbase || 0) * block.membersCount;
502
503
    } else {
      block.monetaryMass = 0
504
505
506
507
508
509
510
511
512
513
    }
    // UD Time update
    if (block.number == 0) {
      block.dividend = null;
    }
    else if (!block.dividend) {
      block.dividend = null;
    }
  }

514
  static pushStatsForBlocks(blocks:BlockDTO[], dal:FileDAL) {
515
    const stats: { [k:string]: { blocks: number[], lastParsedBlock:number }} = {};
516
517
    // Stats
    for (const block of blocks) {
518
519
520
521
522
523
524
525
526
527
528
529
530
531
      const values = [
        { name: 'newcomers', value: block.identities },
        { name: 'certs',     value: block.certifications },
        { name: 'joiners',   value: block.joiners },
        { name: 'actives',   value: block.actives },
        { name: 'leavers',   value: block.leavers },
        { name: 'revoked',   value: block.revoked },
        { name: 'excluded',  value: block.excluded },
        { name: 'ud',        value: block.dividend },
        { name: 'tx',        value: block.transactions }
      ]
      for (const element of values) {
        if (!stats[element.name]) {
          stats[element.name] = { blocks: [], lastParsedBlock: -1 };
532
        }
533
534
535
        const stat = stats[element.name]
        const isPositiveValue = element.value && typeof element.value != 'object';
        const isNonEmptyArray = element.value && typeof element.value == 'object' && element.value.length > 0;
536
537
538
539
540
541
542
543
544
        if (isPositiveValue || isNonEmptyArray) {
          stat.blocks.push(block.number);
        }
        stat.lastParsedBlock = block.number;
      }
    }
    return dal.pushStats(stats);
  }

Cédric Moreau's avatar
Cédric Moreau committed
545
  static async pushSideBlock(obj:BlockDTO, dal:FileDAL, logger:any) {
546
    const start = Date.now();
547
    const block = DBBlock.fromBlockDTO(BlockDTO.fromJSONObject(obj))
548
549
550
551
552
    block.fork = true;
    try {
      // Saves the block (DAL)
      block.wrong = false;
      await dal.saveSideBlockInFile(block);
553
      logger.info('SIDE Block #%s-%s added to the blockchain in %s ms', block.number, block.hash.substr(0, 8), (Date.now() - start));
554
555
556
557
558
559
      return block;
    } catch (err) {
      throw err;
    }
  }
}