From a86c24f9f3970cd5dee40278a36ec3d911efcb18 Mon Sep 17 00:00:00 2001
From: cgeek <cem.moreau@gmail.com>
Date: Thu, 13 Jul 2017 18:07:12 +0200
Subject: [PATCH] [enh] #1037 Migrate indexer.js + blockchainContext.js

---
 .eslintignore                                 |    5 +
 .gitignore                                    |    8 +-
 app/lib/blockchain/BasicBlockchain.ts         |    6 +-
 app/lib/blockchain/DuniterBlockchain.ts       |  217 ++-
 app/lib/blockchain/IndexedBlockchain.ts       |   31 +-
 app/lib/blockchain/MiscIndexedBlockchain.ts   |    7 +-
 app/lib/blockchain/SqlBlockchain.ts           |    2 +-
 .../interfaces/BlockchainOperator.ts          |    2 +-
 app/lib/common.ts                             |    5 +
 app/lib/computation/BlockchainContext.ts      |  159 ++
 app/lib/computation/QuickSync.ts              |  264 ++++
 app/lib/computation/blockchainContext.js      |  145 --
 app/lib/computation/quickSync.js              |  265 ----
 app/lib/dal/fileDAL.js                        |    2 +-
 app/lib/dal/sqliteDAL/AbstractIndex.js        |    2 +-
 app/lib/dal/sqliteDAL/index/CIndexDAL.js      |    2 +-
 app/lib/dal/sqliteDAL/index/IIndexDAL.js      |    2 +-
 app/lib/dal/sqliteDAL/index/MIndexDAL.js      |    2 +-
 app/lib/dal/sqliteDAL/index/SIndexDAL.js      |    2 +-
 app/lib/db/DBBlock.ts                         |   74 +
 app/lib/db/DBHead.ts                          |   38 +
 app/lib/db/DBTransaction.ts                   |   58 +
 app/lib/dto/BlockDTO.ts                       |  144 ++
 app/lib/dto/CertificationDTO.ts               |   14 +
 app/lib/dto/ConfDTO.ts                        |   35 +
 app/lib/dto/IdentityDTO.ts                    |   32 +
 app/lib/dto/RevocationDTO.ts                  |   12 +
 app/lib/dto/TransactionDTO.ts                 |  150 ++
 app/lib/{indexer.js => indexer.ts}            | 1340 ++++++++++-------
 app/lib/rules/global_rules.js                 |   14 +-
 app/lib/rules/local_rules.js                  |   39 +-
 app/modules/prover/lib/blockGenerator.js      |    7 +-
 app/service/BlockchainService.js              |   19 +-
 app/service/TransactionsService.js            |    6 +-
 test/dal/source_dal.js                        |    2 +-
 test/dal/triming.js                           |    2 +-
 test/fast/block_local.js                      |    7 +-
 test/fast/protocol-brg106-number.js           |    2 +-
 test/fast/protocol-brg107-udEffectiveTime.js  |    2 +-
 test/fast/protocol-brg11-udTime.js            |    2 +-
 test/fast/protocol-brg13-dividend.js          |    2 +-
 test/fast/protocol-brg49-version.js           |    2 +-
 test/fast/protocol-brg50-blocksize.js         |    2 +-
 test/fast/protocol-brg51-number.js            |    2 +-
 test/fast/v1.0-local-index.js                 |    5 +-
 test/integration/branches_revert2.js          |  127 +-
 tsconfig.json                                 |    4 +-
 47 files changed, 2093 insertions(+), 1178 deletions(-)
 create mode 100644 app/lib/common.ts
 create mode 100644 app/lib/computation/BlockchainContext.ts
 create mode 100644 app/lib/computation/QuickSync.ts
 delete mode 100644 app/lib/computation/blockchainContext.js
 delete mode 100644 app/lib/computation/quickSync.js
 create mode 100644 app/lib/db/DBBlock.ts
 create mode 100644 app/lib/db/DBHead.ts
 create mode 100644 app/lib/db/DBTransaction.ts
 create mode 100644 app/lib/dto/BlockDTO.ts
 create mode 100644 app/lib/dto/CertificationDTO.ts
 create mode 100644 app/lib/dto/ConfDTO.ts
 create mode 100644 app/lib/dto/IdentityDTO.ts
 create mode 100644 app/lib/dto/RevocationDTO.ts
 create mode 100644 app/lib/dto/TransactionDTO.ts
 rename app/lib/{indexer.js => indexer.ts} (51%)

diff --git a/.eslintignore b/.eslintignore
index e2dd35aa5..f208f45df 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,4 +1,9 @@
 app/lib/blockchain/*.js
 app/lib/blockchain/interfaces/*.js
+app/lib/computation/*.js
+app/lib/db/*.js
+app/lib/dto/*.js
+app/lib/indexer.js
+app/lib/common.js
 test/blockchain/*.js
 test/blockchain/lib/*.js
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index d51ee51c1..304462b9e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,4 +35,10 @@ test/blockchain/lib/*.js.map
 app/lib/blockchain/*.js
 app/lib/blockchain/*.js.map
 app/lib/blockchain/interfaces/*.js
-app/lib/blockchain/interfaces/*.js.map
\ No newline at end of file
+app/lib/blockchain/interfaces/*.js.map
+app/lib/computation/*.js
+app/lib/computation/*.js.map
+app/lib/common.js*
+app/lib/db/*.js*
+app/lib/dto/*.js*
+app/lib/indexer.js*
\ No newline at end of file
diff --git a/app/lib/blockchain/BasicBlockchain.ts b/app/lib/blockchain/BasicBlockchain.ts
index d251b4111..dbf9fbabd 100644
--- a/app/lib/blockchain/BasicBlockchain.ts
+++ b/app/lib/blockchain/BasicBlockchain.ts
@@ -9,7 +9,7 @@ export class BasicBlockchain {
   /**
    * Adds a block at the end of the blockchain.
    */
-  pushBlock(b) {
+  pushBlock(b:any) {
     return this.op.store(b)
   }
 
@@ -18,7 +18,7 @@ export class BasicBlockchain {
    * @param number block ID.
    * @returns {*} Promise<Block>
    */
-  getBlock(number) {
+  getBlock(number:number) {
     return this.op.read(number)
   }
 
@@ -44,7 +44,7 @@ export class BasicBlockchain {
    * @param n Quantity from top. E.g. `1` = [HEAD], `3` = [HEAD, HEAD~1, HEAD~2], etc.
    * @returns {*} Promise<Block>
    */
-  headRange(n) {
+  headRange(n:number) {
     return this.op.headRange(n)
   }
 
diff --git a/app/lib/blockchain/DuniterBlockchain.ts b/app/lib/blockchain/DuniterBlockchain.ts
index ea6a9a465..2de2ea33e 100644
--- a/app/lib/blockchain/DuniterBlockchain.ts
+++ b/app/lib/blockchain/DuniterBlockchain.ts
@@ -1,9 +1,15 @@
 import {MiscIndexedBlockchain} from "./MiscIndexedBlockchain"
+import {IindexEntry, IndexEntry, Indexer, MindexEntry, SindexEntry} from "../indexer"
+import {BlockchainOperator} from "./interfaces/BlockchainOperator"
+import {ConfDTO} from "../dto/ConfDTO"
+import {BlockDTO} from "../dto/BlockDTO"
+import {DBHead} from "../db/DBHead"
+import {IdentityDTO} from "../dto/IdentityDTO"
+import {DBBlock} from "../db/DBBlock"
 
 const _ = require('underscore')
 const Q = require('q')
 const rules = require('../rules')
-const indexer = require('../indexer')
 const common          = require('duniter-common')
 const Block           = require('../entity/block')
 const Identity        = require('../entity/identity')
@@ -11,137 +17,123 @@ const Certification   = require('../entity/certification')
 const Membership      = require('../entity/membership')
 const Transaction     = require('../entity/transaction')
 
-const statTests = {
-  'newcomers': 'identities',
-  'certs': 'certifications',
-  'joiners': 'joiners',
-  'actives': 'actives',
-  'leavers': 'leavers',
-  'revoked': 'revoked',
-  'excluded': 'excluded',
-  'ud': 'dividend',
-  'tx': 'transactions'
-};
-
-const statNames = ['newcomers', 'certs', 'joiners', 'actives', 'leavers', 'revoked', 'excluded', 'ud', 'tx'];
-
 export class DuniterBlockchain extends MiscIndexedBlockchain {
 
-  constructor(blockchainStorage, dal) {
+  constructor(blockchainStorage:BlockchainOperator, dal:any) {
     super(blockchainStorage, dal.mindexDAL, dal.iindexDAL, dal.sindexDAL, dal.cindexDAL)
   }
 
-  async checkBlock(block, withPoWAndSignature, conf, dal) {
-    const index = indexer.localIndex(block, conf)
+  async checkBlock(block:BlockDTO, withPoWAndSignature:boolean, conf: ConfDTO, dal:any) {
+    const index = Indexer.localIndex(block, conf)
     if (withPoWAndSignature) {
       await rules.CHECK.ASYNC.ALL_LOCAL(block, conf, index)
     }
     else {
       await rules.CHECK.ASYNC.ALL_LOCAL_BUT_POW(block, conf, index)
     }
-    const HEAD = await indexer.completeGlobalScope(block, conf, index, dal);
+    const HEAD = await Indexer.completeGlobalScope(block, conf, index, dal);
     const HEAD_1 = await dal.bindexDAL.head(1);
-    const mindex = indexer.mindex(index);
-    const iindex = indexer.iindex(index);
-    const sindex = indexer.sindex(index);
-    const cindex = indexer.cindex(index);
+    const mindex = Indexer.mindex(index);
+    const iindex = Indexer.iindex(index);
+    const sindex = Indexer.sindex(index);
+    const cindex = Indexer.cindex(index);
     // BR_G49
-    if (indexer.ruleVersion(HEAD, HEAD_1) === false) throw Error('ruleVersion');
+    if (Indexer.ruleVersion(HEAD, HEAD_1) === false) throw Error('ruleVersion');
     // BR_G50
-    if (indexer.ruleBlockSize(HEAD) === false) throw Error('ruleBlockSize');
+    if (Indexer.ruleBlockSize(HEAD) === false) throw Error('ruleBlockSize');
     // BR_G98
-    if (indexer.ruleCurrency(block, HEAD) === false) throw Error('ruleCurrency');
+    if (Indexer.ruleCurrency(block, HEAD) === false) throw Error('ruleCurrency');
     // BR_G51
-    if (indexer.ruleNumber(block, HEAD) === false) throw Error('ruleNumber');
+    if (Indexer.ruleNumber(block, HEAD) === false) throw Error('ruleNumber');
     // BR_G52
-    if (indexer.rulePreviousHash(block, HEAD) === false) throw Error('rulePreviousHash');
+    if (Indexer.rulePreviousHash(block, HEAD) === false) throw Error('rulePreviousHash');
     // BR_G53
-    if (indexer.rulePreviousIssuer(block, HEAD) === false) throw Error('rulePreviousIssuer');
+    if (Indexer.rulePreviousIssuer(block, HEAD) === false) throw Error('rulePreviousIssuer');
     // BR_G101
-    if (indexer.ruleIssuerIsMember(HEAD) === false) throw Error('ruleIssuerIsMember');
+    if (Indexer.ruleIssuerIsMember(HEAD) === false) throw Error('ruleIssuerIsMember');
     // BR_G54
-    if (indexer.ruleIssuersCount(block, HEAD) === false) throw Error('ruleIssuersCount');
+    if (Indexer.ruleIssuersCount(block, HEAD) === false) throw Error('ruleIssuersCount');
     // BR_G55
-    if (indexer.ruleIssuersFrame(block, HEAD) === false) throw Error('ruleIssuersFrame');
+    if (Indexer.ruleIssuersFrame(block, HEAD) === false) throw Error('ruleIssuersFrame');
     // BR_G56
-    if (indexer.ruleIssuersFrameVar(block, HEAD) === false) throw Error('ruleIssuersFrameVar');
+    if (Indexer.ruleIssuersFrameVar(block, HEAD) === false) throw Error('ruleIssuersFrameVar');
     // BR_G57
-    if (indexer.ruleMedianTime(block, HEAD) === false) throw Error('ruleMedianTime');
+    if (Indexer.ruleMedianTime(block, HEAD) === false) throw Error('ruleMedianTime');
     // BR_G58
-    if (indexer.ruleDividend(block, HEAD) === false) throw Error('ruleDividend');
+    if (Indexer.ruleDividend(block, HEAD) === false) throw Error('ruleDividend');
     // BR_G59
-    if (indexer.ruleUnitBase(block, HEAD) === false) throw Error('ruleUnitBase');
+    if (Indexer.ruleUnitBase(block, HEAD) === false) throw Error('ruleUnitBase');
     // BR_G60
-    if (indexer.ruleMembersCount(block, HEAD) === false) throw Error('ruleMembersCount');
+    if (Indexer.ruleMembersCount(block, HEAD) === false) throw Error('ruleMembersCount');
     // BR_G61
-    if (indexer.rulePowMin(block, HEAD) === false) throw Error('rulePowMin');
+    if (Indexer.rulePowMin(block, HEAD) === false) throw Error('rulePowMin');
     if (withPoWAndSignature) {
       // BR_G62
-      if (indexer.ruleProofOfWork(HEAD) === false) throw Error('ruleProofOfWork');
+      if (Indexer.ruleProofOfWork(HEAD) === false) throw Error('ruleProofOfWork');
     }
     // BR_G63
-    if (indexer.ruleIdentityWritability(iindex, conf) === false) throw Error('ruleIdentityWritability');
+    if (Indexer.ruleIdentityWritability(iindex, conf) === false) throw Error('ruleIdentityWritability');
     // BR_G64
-    if (indexer.ruleMembershipWritability(mindex, conf) === false) throw Error('ruleMembershipWritability');
+    if (Indexer.ruleMembershipWritability(mindex, conf) === false) throw Error('ruleMembershipWritability');
     // BR_G108
-    if (indexer.ruleMembershipPeriod(mindex) === false) throw Error('ruleMembershipPeriod');
+    if (Indexer.ruleMembershipPeriod(mindex) === false) throw Error('ruleMembershipPeriod');
     // BR_G65
-    if (indexer.ruleCertificationWritability(cindex, conf) === false) throw Error('ruleCertificationWritability');
+    if (Indexer.ruleCertificationWritability(cindex, conf) === false) throw Error('ruleCertificationWritability');
     // BR_G66
-    if (indexer.ruleCertificationStock(cindex, conf) === false) throw Error('ruleCertificationStock');
+    if (Indexer.ruleCertificationStock(cindex, conf) === false) throw Error('ruleCertificationStock');
     // BR_G67
-    if (indexer.ruleCertificationPeriod(cindex) === false) throw Error('ruleCertificationPeriod');
+    if (Indexer.ruleCertificationPeriod(cindex) === false) throw Error('ruleCertificationPeriod');
     // BR_G68
-    if (indexer.ruleCertificationFromMember(HEAD, cindex) === false) throw Error('ruleCertificationFromMember');
+    if (Indexer.ruleCertificationFromMember(HEAD, cindex) === false) throw Error('ruleCertificationFromMember');
     // BR_G69
-    if (indexer.ruleCertificationToMemberOrNewcomer(cindex) === false) throw Error('ruleCertificationToMemberOrNewcomer');
+    if (Indexer.ruleCertificationToMemberOrNewcomer(cindex) === false) throw Error('ruleCertificationToMemberOrNewcomer');
     // BR_G70
-    if (indexer.ruleCertificationToLeaver(cindex) === false) throw Error('ruleCertificationToLeaver');
+    if (Indexer.ruleCertificationToLeaver(cindex) === false) throw Error('ruleCertificationToLeaver');
     // BR_G71
-    if (indexer.ruleCertificationReplay(cindex) === false) throw Error('ruleCertificationReplay');
+    if (Indexer.ruleCertificationReplay(cindex) === false) throw Error('ruleCertificationReplay');
     // BR_G72
-    if (indexer.ruleCertificationSignature(cindex) === false) throw Error('ruleCertificationSignature');
+    if (Indexer.ruleCertificationSignature(cindex) === false) throw Error('ruleCertificationSignature');
     // BR_G73
-    if (indexer.ruleIdentityUIDUnicity(iindex) === false) throw Error('ruleIdentityUIDUnicity');
+    if (Indexer.ruleIdentityUIDUnicity(iindex) === false) throw Error('ruleIdentityUIDUnicity');
     // BR_G74
-    if (indexer.ruleIdentityPubkeyUnicity(iindex) === false) throw Error('ruleIdentityPubkeyUnicity');
+    if (Indexer.ruleIdentityPubkeyUnicity(iindex) === false) throw Error('ruleIdentityPubkeyUnicity');
     // BR_G75
-    if (indexer.ruleMembershipSuccession(mindex) === false) throw Error('ruleMembershipSuccession');
+    if (Indexer.ruleMembershipSuccession(mindex) === false) throw Error('ruleMembershipSuccession');
     // BR_G76
-    if (indexer.ruleMembershipDistance(HEAD, mindex) === false) throw Error('ruleMembershipDistance');
+    if (Indexer.ruleMembershipDistance(HEAD, mindex) === false) throw Error('ruleMembershipDistance');
     // BR_G77
-    if (indexer.ruleMembershipOnRevoked(mindex) === false) throw Error('ruleMembershipOnRevoked');
+    if (Indexer.ruleMembershipOnRevoked(mindex) === false) throw Error('ruleMembershipOnRevoked');
     // BR_G78
-    if (indexer.ruleMembershipJoinsTwice(mindex) === false) throw Error('ruleMembershipJoinsTwice');
+    if (Indexer.ruleMembershipJoinsTwice(mindex) === false) throw Error('ruleMembershipJoinsTwice');
     // BR_G79
-    if (indexer.ruleMembershipEnoughCerts(mindex) === false) throw Error('ruleMembershipEnoughCerts');
+    if (Indexer.ruleMembershipEnoughCerts(mindex) === false) throw Error('ruleMembershipEnoughCerts');
     // BR_G80
-    if (indexer.ruleMembershipLeaverIsMember(mindex) === false) throw Error('ruleMembershipLeaverIsMember');
+    if (Indexer.ruleMembershipLeaverIsMember(mindex) === false) throw Error('ruleMembershipLeaverIsMember');
     // BR_G81
-    if (indexer.ruleMembershipActiveIsMember(mindex) === false) throw Error('ruleMembershipActiveIsMember');
+    if (Indexer.ruleMembershipActiveIsMember(mindex) === false) throw Error('ruleMembershipActiveIsMember');
     // BR_G82
-    if (indexer.ruleMembershipRevokedIsMember(mindex) === false) throw Error('ruleMembershipRevokedIsMember');
+    if (Indexer.ruleMembershipRevokedIsMember(mindex) === false) throw Error('ruleMembershipRevokedIsMember');
     // BR_G83
-    if (indexer.ruleMembershipRevokedSingleton(mindex) === false) throw Error('ruleMembershipRevokedSingleton');
+    if (Indexer.ruleMembershipRevokedSingleton(mindex) === false) throw Error('ruleMembershipRevokedSingleton');
     // BR_G84
-    if (indexer.ruleMembershipRevocationSignature(mindex) === false) throw Error('ruleMembershipRevocationSignature');
+    if (Indexer.ruleMembershipRevocationSignature(mindex) === false) throw Error('ruleMembershipRevocationSignature');
     // BR_G85
-    if (indexer.ruleMembershipExcludedIsMember(iindex) === false) throw Error('ruleMembershipExcludedIsMember');
+    if (Indexer.ruleMembershipExcludedIsMember(iindex) === false) throw Error('ruleMembershipExcludedIsMember');
     // BR_G86
-    if ((await indexer.ruleToBeKickedArePresent(iindex, dal)) === false) throw Error('ruleToBeKickedArePresent');
+    if ((await Indexer.ruleToBeKickedArePresent(iindex, dal)) === false) throw Error('ruleToBeKickedArePresent');
     // BR_G103
-    if (indexer.ruleTxWritability(sindex) === false) throw Error('ruleTxWritability');
+    if (Indexer.ruleTxWritability(sindex) === false) throw Error('ruleTxWritability');
     // BR_G87
-    if (indexer.ruleInputIsAvailable(sindex) === false) throw Error('ruleInputIsAvailable');
+    if (Indexer.ruleInputIsAvailable(sindex) === false) throw Error('ruleInputIsAvailable');
     // BR_G88
-    if (indexer.ruleInputIsUnlocked(sindex) === false) throw Error('ruleInputIsUnlocked');
+    if (Indexer.ruleInputIsUnlocked(sindex) === false) throw Error('ruleInputIsUnlocked');
     // BR_G89
-    if (indexer.ruleInputIsTimeUnlocked(sindex) === false) throw Error('ruleInputIsTimeUnlocked');
+    if (Indexer.ruleInputIsTimeUnlocked(sindex) === false) throw Error('ruleInputIsTimeUnlocked');
     // BR_G90
-    if (indexer.ruleOutputBase(sindex, HEAD_1) === false) throw Error('ruleOutputBase');
+    if (Indexer.ruleOutputBase(sindex, HEAD_1) === false) throw Error('ruleOutputBase');
     // Check document's coherence
 
-    const matchesList = (regexp, list) => {
+    const matchesList = (regexp:RegExp, list:string[]) => {
       let i = 0;
       let found = "";
       while (!found && i < list.length) {
@@ -169,7 +161,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     return { index, HEAD }
   }
 
-  async pushTheBlock(obj, index, HEAD, conf, dal, logger) {
+  async pushTheBlock(obj:BlockDTO, index:IndexEntry[], HEAD:DBHead, conf:ConfDTO, dal:any, logger:any) {
     const start = Date.now();
     const block = new Block(obj);
     try {
@@ -196,7 +188,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     // await supra.recordIndex(index)
   }
 
-  async saveBlockData(current, block, conf, dal, logger, index, HEAD) {
+  async saveBlockData(current:DBBlock, block:BlockDTO, conf:ConfDTO, dal:any, logger:any, index:IndexEntry[], HEAD:DBHead) {
     if (block.number == 0) {
       await this.saveParametersForRoot(block, conf, dal);
     }
@@ -234,9 +226,10 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
       await dal.trimIndexes(indexes.HEAD.number - MAX_BINDEX_SIZE);
     }
 
-    await this.updateBlocksComputedVars(current, block);
+    const dbb = DBBlock.fromBlockDTO(block)
+    await this.updateBlocksComputedVars(current, dbb);
     // Saves the block (DAL)
-    await dal.saveBlock(block);
+    await dal.saveBlock(dbb);
 
     // --> Update links
     await dal.updateWotbLinks(indexes.cindex);
@@ -255,7 +248,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     return block;
   }
 
-  async saveParametersForRoot(block, conf, dal) {
+  async saveParametersForRoot(block:BlockDTO, conf:ConfDTO, dal:any) {
     if (block.parameters) {
       const bconf = Block.statics.getConf(block);
       conf.c = bconf.c;
@@ -285,27 +278,20 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     }
   }
 
-  async createNewcomers(iindex, dal, logger) {
+  async createNewcomers(iindex:IindexEntry[], dal:any, logger:any) {
     for (const entry of iindex) {
       if (entry.op == common.constants.IDX_CREATE) {
         // 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.
-        await this.cleanRejectedIdentities({
-          pubkey: entry.pub,
-          uid: entry.uid
-        }, dal);
+        await dal.removeUnWrittenWithPubkey(entry.pub)
+        await dal.removeUnWrittenWithUID(entry.uid)
       }
     }
   }
 
-  async cleanRejectedIdentities(idty, dal) {
-    await dal.removeUnWrittenWithPubkey(idty.pubkey);
-    await dal.removeUnWrittenWithUID(idty.uid);
-  }
-
-  async updateMembers(block, dal) {
+  async updateMembers(block:BlockDTO, dal:any) {
     // Joiners (come back)
     for (const inlineMS of block.joiners) {
       let ms = Membership.statics.fromInline(inlineMS);
@@ -324,13 +310,13 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     }
   }
 
-  async updateWallets(sindex, aDal, reverse = false) {
+  async updateWallets(sindex:SindexEntry[], aDal:any, reverse = false) {
     const differentConditions = _.uniq(sindex.map((entry) => entry.conditions))
     for (const conditions of differentConditions) {
-      const creates = _.filter(sindex, (entry) => entry.conditions === conditions && entry.op === common.constants.IDX_CREATE)
-      const updates = _.filter(sindex, (entry) => entry.conditions === conditions && entry.op === common.constants.IDX_UPDATE)
-      const positives = creates.reduce((sum, src) => sum + src.amount * Math.pow(10, src.base), 0)
-      const negatives = updates.reduce((sum, src) => sum + src.amount * Math.pow(10, src.base), 0)
+      const creates = _.filter(sindex, (entry:SindexEntry) => entry.conditions === conditions && entry.op === common.constants.IDX_CREATE)
+      const updates = _.filter(sindex, (entry:SindexEntry) => entry.conditions === conditions && entry.op === common.constants.IDX_UPDATE)
+      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)
       const wallet = await aDal.getWallet(conditions)
       let variation = positives - negatives
       if (reverse) {
@@ -342,7 +328,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     }
   }
 
-  async revertBlock(number, hash, dal) {
+  async revertBlock(number:number, hash:string, dal:any) {
 
     const blockstamp = [number, hash].join('-');
 
@@ -386,7 +372,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     await this.undoDeleteTransactions(block, dal)
   }
 
-  async undoMembersUpdate(blockstamp, dal) {
+  async undoMembersUpdate(blockstamp:string, dal:any) {
     const joiners = await dal.iindexDAL.getWrittenOn(blockstamp);
     for (const entry of joiners) {
       // Undo 'join' which can be either newcomers or comebackers
@@ -416,7 +402,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     }
   }
 
-  async undoDeleteTransactions(block, dal) {
+  async undoDeleteTransactions(block:BlockDTO, dal:any) {
     for (const obj of block.transactions) {
       obj.currency = block.currency;
       let tx = new Transaction(obj);
@@ -430,7 +416,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
    * @param block Block in which are contained the certifications to remove from sandbox.
    * @param dal The DAL
    */
-  async removeCertificationsFromSandbox(block, dal) {
+  async removeCertificationsFromSandbox(block:BlockDTO, dal:any) {
     for (let inlineCert of block.certifications) {
       let cert = Certification.statics.fromInline(inlineCert);
       let idty = await dal.getWritten(cert.to);
@@ -445,7 +431,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
    * @param block Block in which are contained the certifications to remove from sandbox.
    * @param dal The DAL
    */
-  async removeMembershipsFromSandbox(block, dal) {
+  async removeMembershipsFromSandbox(block:BlockDTO, dal:any) {
     const mss = block.joiners.concat(block.actives).concat(block.leavers);
     for (const inlineMS of mss) {
       let ms = Membership.statics.fromInline(inlineMS);
@@ -453,14 +439,14 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     }
   }
 
-  async computeToBeRevoked(mindex, dal) {
-    const revocations = _.filter(mindex, (entry) => entry.revoked_on);
+  async computeToBeRevoked(mindex:MindexEntry[], dal:any) {
+    const revocations = _.filter(mindex, (entry:MindexEntry) => entry.revoked_on);
     for (const revoked of revocations) {
       await dal.setRevoked(revoked.pub, true);
     }
   }
 
-  async deleteTransactions(block, dal) {
+  async deleteTransactions(block:BlockDTO, dal:any) {
     for (const obj of block.transactions) {
       obj.currency = block.currency;
       const tx = new Transaction(obj);
@@ -469,7 +455,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     }
   }
 
-  updateBlocksComputedVars(current, block): Promise<void> {
+  updateBlocksComputedVars(current:DBBlock, block:DBBlock): Promise<void> {
     // Unit Base
     block.unitbase = (block.dividend && block.unitbase) || (current && current.unitbase) || 0;
     // Monetary Mass update
@@ -487,19 +473,28 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     return Promise.resolve()
   }
 
-  static pushStatsForBlocks(blocks, dal) {
-    const stats = {};
+  static pushStatsForBlocks(blocks:BlockDTO[], dal:any) {
+    const stats: { [k:string]: { blocks: number[], lastParsedBlock:number }} = {};
     // Stats
     for (const block of blocks) {
-      for (const statName of statNames) {
-        if (!stats[statName]) {
-          stats[statName] = { blocks: [] };
+      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 };
         }
-        const stat = stats[statName];
-        const testProperty = statTests[statName];
-        const value = block[testProperty];
-        const isPositiveValue = value && typeof value != 'object';
-        const isNonEmptyArray = value && typeof value == 'object' && value.length > 0;
+        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;
         if (isPositiveValue || isNonEmptyArray) {
           stat.blocks.push(block.number);
         }
@@ -509,7 +504,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain {
     return dal.pushStats(stats);
   }
 
-  async pushSideBlock(obj, dal, logger) {
+  async pushSideBlock(obj:BlockDTO, dal:any, logger:any) {
     const start = Date.now();
     const block = new Block(obj);
     block.fork = true;
diff --git a/app/lib/blockchain/IndexedBlockchain.ts b/app/lib/blockchain/IndexedBlockchain.ts
index 67fa5a091..2545c3b66 100644
--- a/app/lib/blockchain/IndexedBlockchain.ts
+++ b/app/lib/blockchain/IndexedBlockchain.ts
@@ -2,32 +2,33 @@
 import {BasicBlockchain} from "./BasicBlockchain"
 import {IndexOperator} from "./interfaces/IndexOperator"
 import {BlockchainOperator} from "./interfaces/BlockchainOperator"
-import * as _ from "underscore"
+
+const _ = require('underscore')
 
 export class IndexedBlockchain extends BasicBlockchain {
 
   private initIndexer: Promise<void>
 
-  constructor(bcOperations: BlockchainOperator, private indexOperations: IndexOperator, private numberField, private pkFields: any) {
+  constructor(bcOperations: BlockchainOperator, private indexOperations: IndexOperator, private numberField: string, private pkFields: any) {
     super(bcOperations)
     this.initIndexer = indexOperations.initIndexer(pkFields)
   }
 
-  async recordIndex(index) {
+  async recordIndex(index: { [index: string]: any }) {
     // Wait indexer init
     await this.initIndexer
 
     return this.indexOperations.recordIndex(index)
   }
 
-  async indexTrim(maxNumber) {
+  async indexTrim(maxNumber:number) {
 
     // Wait indexer init
     await this.initIndexer
 
     const subIndexes = await this.indexOperations.getSubIndexes()
     // Trim the subIndexes
-    const records = {}
+    const records: { [index: string]: any } = {}
     for (const subIndex of subIndexes) {
       records[subIndex] = []
       const pks = typeof this.pkFields[subIndex].pk !== 'string' && this.pkFields[subIndex].pk.length ? Array.from(this.pkFields[subIndex].pk) : [this.pkFields[subIndex].pk]
@@ -57,7 +58,7 @@ export class IndexedBlockchain extends BasicBlockchain {
     return Promise.resolve()
   }
 
-  async indexCount(indexName, criterias) {
+  async indexCount(indexName: string, criterias: { [index: string]: any }) {
 
     // Wait indexer init
     await this.initIndexer
@@ -66,7 +67,7 @@ export class IndexedBlockchain extends BasicBlockchain {
     return records.length
   }
 
-  async indexReduce(indexName, criterias) {
+  async indexReduce(indexName: string, criterias: { [index: string]: any }) {
 
     // Wait indexer init
     await this.initIndexer
@@ -75,7 +76,7 @@ export class IndexedBlockchain extends BasicBlockchain {
     return reduce(records)
   }
 
-  async indexReduceGroupBy(indexName, criterias, properties) {
+  async indexReduceGroupBy(indexName: string, criterias: { [index: string]: any }, properties: string[]) {
 
     // Wait indexer init
     await this.initIndexer
@@ -84,17 +85,17 @@ export class IndexedBlockchain extends BasicBlockchain {
     return reduceBy(records, properties)
   }
 
-  async indexRevert(blockNumber) {
+  async indexRevert(blockNumber:number) {
     const subIndexes = await this.indexOperations.getSubIndexes()
     for (const subIndex of subIndexes) {
-      const removeCriterias = {}
+      const removeCriterias: { [index: string]: any } = {}
       removeCriterias[this.numberField] = blockNumber
       await this.indexOperations.removeWhere(subIndex, removeCriterias)
     }
   }
 }
 
-function reduce(records) {
+function reduce(records: any[]) {
   return records.reduce((obj, record) => {
     const keys = Object.keys(record);
     for (const k of keys) {
@@ -106,18 +107,18 @@ function reduce(records) {
   }, {});
 }
 
-function reduceBy(reducables, properties) {
+function reduceBy(reducables: any[], properties: string[]) {
   const reduced = reducables.reduce((map, entry) => {
     const id = properties.map((prop) => entry[prop]).join('-');
     map[id] = map[id] || [];
     map[id].push(entry);
     return map;
   }, {});
-  return _.values(reduced).map((value) => reduce(value))
+  return _.values(reduced).map((rows: any[]) => reduce(rows))
 }
 
-function criteriasFromPks(pks, values) {
-  const criterias = {}
+function criteriasFromPks(pks: string[], values: any): { [index: string]: any } {
+  const criterias: { [index: string]: any } = {}
   for (const key of pks) {
     criterias[key] = values[key]
   }
diff --git a/app/lib/blockchain/MiscIndexedBlockchain.ts b/app/lib/blockchain/MiscIndexedBlockchain.ts
index 05b7acdb9..dbde55274 100644
--- a/app/lib/blockchain/MiscIndexedBlockchain.ts
+++ b/app/lib/blockchain/MiscIndexedBlockchain.ts
@@ -1,20 +1,21 @@
 "use strict"
 import {IndexedBlockchain} from "./IndexedBlockchain"
 import {SQLIndex} from "./SqlIndex"
+import {BlockchainOperator} from "./interfaces/BlockchainOperator"
 
 export class MiscIndexedBlockchain extends IndexedBlockchain {
 
-  constructor(blockchainStorage, mindexDAL, iindexDAL, sindexDAL, cindexDAL) {
+  constructor(blockchainStorage: BlockchainOperator, mindexDAL:any, iindexDAL:any, sindexDAL:any, cindexDAL:any) {
     super(blockchainStorage, new SQLIndex(null, {
       m_index: { handler: mindexDAL },
       i_index: { handler: iindexDAL },
       s_index: {
         handler: sindexDAL,
-        findTrimable: (maxNumber) => sindexDAL.query('SELECT * FROM s_index WHERE consumed AND writtenOn < ?', [maxNumber])
+        findTrimable: (maxNumber:number) => sindexDAL.query('SELECT * FROM s_index WHERE consumed AND writtenOn < ?', [maxNumber])
       },
       c_index: {
         handler: cindexDAL,
-        findTrimable: (maxNumber) => cindexDAL.query('SELECT * FROM c_index WHERE expired_on > 0 AND writtenOn < ?', [maxNumber])
+        findTrimable: (maxNumber:number) => cindexDAL.query('SELECT * FROM c_index WHERE expired_on > 0 AND writtenOn < ?', [maxNumber])
       }
     }), 'writtenOn', {
       m_index: {
diff --git a/app/lib/blockchain/SqlBlockchain.ts b/app/lib/blockchain/SqlBlockchain.ts
index b2037c306..7b474199b 100644
--- a/app/lib/blockchain/SqlBlockchain.ts
+++ b/app/lib/blockchain/SqlBlockchain.ts
@@ -1,7 +1,7 @@
 "use strict"
 import {BlockchainOperator} from "./interfaces/BlockchainOperator"
 
-const indexer = require('../../lib/indexer')
+const indexer = require('../../lib/indexer').Indexer
 
 export class SQLBlockchain implements BlockchainOperator {
 
diff --git a/app/lib/blockchain/interfaces/BlockchainOperator.ts b/app/lib/blockchain/interfaces/BlockchainOperator.ts
index d1a61b3ff..12e96f11a 100644
--- a/app/lib/blockchain/interfaces/BlockchainOperator.ts
+++ b/app/lib/blockchain/interfaces/BlockchainOperator.ts
@@ -6,7 +6,7 @@ export interface BlockchainOperator {
    * Pushes a new block at the top of the blockchain.
    * @param b Block.
    */
-  store(b):Promise<any>
+  store(b:any):Promise<any>
 
   /**
    * Reads the block at index `i`.
diff --git a/app/lib/common.ts b/app/lib/common.ts
new file mode 100644
index 000000000..a16cf1bdc
--- /dev/null
+++ b/app/lib/common.ts
@@ -0,0 +1,5 @@
+const common = require('duniter-common')
+
+export function hashf(str:string) {
+  return common.hashf(str).toUpperCase()
+}
diff --git a/app/lib/computation/BlockchainContext.ts b/app/lib/computation/BlockchainContext.ts
new file mode 100644
index 000000000..5dc02dd81
--- /dev/null
+++ b/app/lib/computation/BlockchainContext.ts
@@ -0,0 +1,159 @@
+"use strict";
+import {BlockDTO} from "../dto/BlockDTO"
+import {DuniterBlockchain} from "../blockchain/DuniterBlockchain"
+import {QuickSynchronizer} from "./QuickSync"
+import {DBHead} from "../db/DBHead"
+const _               = require('underscore');
+const indexer         = require('../indexer').Indexer
+const constants       = require('../constants');
+const Block           = require('../entity/block');
+
+export class BlockchainContext {
+
+  private conf:any
+  private dal:any
+  private logger:any
+  private blockchain:DuniterBlockchain
+  private quickSynchronizer:QuickSynchronizer
+
+  /**
+   * The virtual next HEAD. Computed each time a new block is added, because a lot of HEAD variables are deterministic
+   * and can be computed one, just after a block is added for later controls.
+   */
+  private vHEAD:any
+
+  /**
+   * The currently written HEAD, aka. HEAD_1 relatively to incoming HEAD.
+   */
+  private vHEAD_1:any
+
+  private HEADrefreshed: Promise<any> | null = Promise.resolve();
+
+  /**
+   * Refresh the virtual HEAD value for determined variables of the next coming block, avoiding to recompute them
+   * each time a new block arrives to check if the values are correct. We can know and store them early on, in vHEAD.
+   */
+  private refreshHead(): Promise<void> {
+    this.HEADrefreshed = (async (): Promise<void> => {
+      this.vHEAD_1 = await this.dal.head(1);
+      // We suppose next block will have same version #, and no particular data in the block (empty index)
+      let block;
+      // But if no HEAD_1 exist, we must initialize a block with default values
+      if (!this.vHEAD_1) {
+        block = {
+          version: constants.BLOCK_GENERATED_VERSION,
+          time: Math.round(Date.now() / 1000),
+          powMin: this.conf.powMin || 0,
+          powZeros: 0,
+          powRemainder: 0,
+          avgBlockSize: 0
+        };
+      } else {
+        block = { version: this.vHEAD_1.version };
+      }
+      this.vHEAD = await indexer.completeGlobalScope(Block.statics.fromJSON(block), this.conf, [], this.dal);
+    })()
+    return this.HEADrefreshed;
+  }
+
+  /**
+   * Gets a copy of vHEAD, extended with some extra properties.
+   * @param props The extra properties to add.
+   */
+  async getvHeadCopy(props: any): Promise<any> {
+    if (!this.vHEAD) {
+      await this.refreshHead();
+    }
+    const copy: any = {};
+    const keys = Object.keys(this.vHEAD);
+    for (const k of keys) {
+      copy[k] = this.vHEAD[k];
+    }
+    _.extend(copy, props);
+    return copy;
+  }
+
+  /**
+   * Get currently written HEAD.
+   */
+  async getvHEAD_1(): Promise<any> {
+    if (!this.vHEAD) {
+      await this.refreshHead();
+    }
+    return this.vHEAD_1
+  }
+
+  /**
+   * Utility method: gives the personalized difficulty level of a given issuer for next block.
+   * @param issuer The issuer we want to get the difficulty level.
+   */
+  async getIssuerPersonalizedDifficulty(issuer: string): Promise<any> {
+    const local_vHEAD = await this.getvHeadCopy({ issuer });
+    await indexer.preparePersonalizedPoW(local_vHEAD, this.vHEAD_1, this.dal.range, this.conf)
+    return local_vHEAD.issuerDiff;
+  }
+
+  setConfDAL(newConf: any, newDAL: any, theBlockchain: DuniterBlockchain, theQuickSynchronizer: QuickSynchronizer): void {
+    this.dal = newDAL;
+    this.conf = newConf;
+    this.blockchain = theBlockchain
+    this.quickSynchronizer = theQuickSynchronizer
+    this.logger = require('../logger')(this.dal.profile);
+  }
+
+  checkBlock(block: BlockDTO, withPoWAndSignature = true): Promise<any> {
+    return this.blockchain.checkBlock(block, withPoWAndSignature, this.conf, this.dal)
+  }
+
+  async addBlock(obj: BlockDTO, index: any, HEAD: DBHead): Promise<any> {
+    const block = await this.blockchain.pushTheBlock(obj, index, HEAD, this.conf, this.dal, this.logger)
+    this.vHEAD_1 = this.vHEAD = this.HEADrefreshed = null
+    return block
+  }
+
+  addSideBlock(obj:BlockDTO): Promise<any> {
+    return this.blockchain.pushSideBlock(obj, this.dal, this.logger)
+  }
+
+  async revertCurrentBlock(): Promise<any> {
+    const head_1 = await this.dal.bindexDAL.head(1);
+    this.logger.debug('Reverting block #%s...', head_1.number);
+    const res = await this.blockchain.revertBlock(head_1.number, head_1.hash, this.dal)
+    this.logger.debug('Reverted block #%s', head_1.number);
+    // Invalidates the head, since it has changed.
+    await this.refreshHead();
+    return res;
+  }
+
+  async applyNextAvailableFork(): Promise<any> {
+    const current = await this.current();
+    this.logger.debug('Find next potential block #%s...', current.number + 1);
+    const forks = await this.dal.getForkBlocksFollowing(current);
+    if (!forks.length) {
+      throw constants.ERRORS.NO_POTENTIAL_FORK_AS_NEXT;
+    }
+    const block = forks[0];
+    const { index, HEAD } = await this.checkBlock(block, constants.WITH_SIGNATURES_AND_POW);
+    await this.addBlock(block, index, HEAD);
+    this.logger.debug('Applied block #%s', block.number);
+  }
+
+  current(): Promise<any> {
+    return this.dal.getCurrentBlockOrNull()
+  }
+
+  async checkHaveEnoughLinks(target: string, newLinks: any): Promise<any> {
+    const links = await this.dal.getValidLinksTo(target);
+    let count = links.length;
+    if (newLinks[target] && newLinks[target].length) {
+      count += newLinks[target].length;
+    }
+    if (count < this.conf.sigQty) {
+      throw 'Key ' + target + ' does not have enough links (' + count + '/' + this.conf.sigQty + ')';
+    }
+  }
+
+  quickApplyBlocks(blocks:BlockDTO[], to: number | null): Promise<any> {
+    return this.quickSynchronizer.quickApplyBlocks(blocks, to)
+  }
+}
diff --git a/app/lib/computation/QuickSync.ts b/app/lib/computation/QuickSync.ts
new file mode 100644
index 000000000..261878e4f
--- /dev/null
+++ b/app/lib/computation/QuickSync.ts
@@ -0,0 +1,264 @@
+"use strict"
+import {DuniterBlockchain} from "../blockchain/DuniterBlockchain"
+import {BlockDTO} from "../dto/BlockDTO"
+import {DBTransaction} from "../db/DBTransaction"
+import {Indexer} from "../indexer"
+import {ConfDTO} from "../dto/ConfDTO"
+
+const Q = require('q');
+const _ = require('underscore')
+const constants = require('../constants')
+const Block = require('../entity/block')
+
+let sync_bindex: any [] = [];
+let sync_iindex: any[] = [];
+let sync_mindex: any[] = [];
+let sync_cindex: any[] = [];
+let sync_sindex: any[] = [];
+let sync_bindexSize = 0;
+let sync_allBlocks: BlockDTO[] = [];
+let sync_expires: number[] = [];
+let sync_nextExpiring = 0;
+let sync_currConf: ConfDTO;
+const sync_memoryWallets: any = {}
+const sync_memoryDAL = {
+  getWallet: (conditions: string) => Promise.resolve(sync_memoryWallets[conditions] || { conditions, balance: 0 }),
+  saveWallet: async (wallet: any) => {
+    // Make a copy
+    sync_memoryWallets[wallet.conditions] = {
+      conditions: wallet.conditions,
+      balance: wallet.balance
+    }
+  },
+  sindexDAL: {
+    getAvailableForConditions: null
+  }
+}
+
+export class QuickSynchronizer {
+
+  constructor(private blockchain:DuniterBlockchain, private conf: any, private dal: any, private logger: any) {
+  }
+
+  async saveBlocksInMainBranch(blocks: BlockDTO[]): Promise<void> {
+    // VERY FIRST: parameters, otherwise we compute wrong variables such as UDTime
+    if (blocks[0].number == 0) {
+      await this.blockchain.saveParametersForRoot(blocks[0], this.conf, this.dal)
+    }
+    // Helper to retrieve a block with local cache
+    const getBlock = (number: number): BlockDTO => {
+      const firstLocalNumber = blocks[0].number;
+      if (number >= firstLocalNumber) {
+        let offset = number - firstLocalNumber;
+        return Q(blocks[offset]);
+      }
+      return this.dal.getBlock(number);
+    };
+    const getBlockByNumberAndHash = async (number: number, hash: string): Promise<BlockDTO> => {
+      const block = await getBlock(number);
+      if (!block || block.hash != hash) {
+        throw 'Block #' + [number, hash].join('-') + ' not found neither in DB nor in applying blocks';
+      }
+      return block;
+    }
+    for (const block of blocks) {
+      block.fork = false;
+    }
+    // Transactions recording
+    await this.updateTransactionsForBlocks(blocks, getBlockByNumberAndHash);
+    await this.dal.blockDAL.saveBunch(blocks);
+    await DuniterBlockchain.pushStatsForBlocks(blocks, this.dal);
+  }
+
+  private async updateTransactionsForBlocks(blocks: BlockDTO[], getBlockByNumberAndHash: (number: number, hash: string) => Promise<BlockDTO>): Promise<any> {
+    let txs: DBTransaction[] = [];
+    for (const block of blocks) {
+      const newOnes: DBTransaction[] = [];
+      for (const tx of block.transactions) {
+        const [number, hash] = tx.blockstamp.split('-')
+        const refBlock: BlockDTO = (await getBlockByNumberAndHash(parseInt(number), hash))
+        // We force the usage of the reference block's currency
+        tx.currency = refBlock.currency
+        tx.hash = tx.getHash()
+        const dbTx: DBTransaction = DBTransaction.fromTransactionDTO(tx, refBlock.medianTime, true, false, refBlock.number, refBlock.medianTime)
+        newOnes.push(dbTx)
+      }
+      txs = txs.concat(newOnes);
+    }
+    return this.dal.updateTransactions(txs);
+  }
+
+  async quickApplyBlocks(blocks:BlockDTO[], to: number | null): Promise<void> {
+
+    sync_memoryDAL.sindexDAL = { getAvailableForConditions: this.dal.sindexDAL.getAvailableForConditions }
+    let blocksToSave: BlockDTO[] = [];
+
+    for (const block of blocks) {
+      sync_allBlocks.push(block);
+
+      // The new kind of object stored
+      const dto = BlockDTO.fromJSONObject(block)
+
+      if (block.number == 0) {
+        sync_currConf = Block.statics.getConf(block);
+      }
+
+      if (block.number != to) {
+        blocksToSave.push(dto);
+        const index:any = Indexer.localIndex(dto, sync_currConf);
+        const local_iindex = Indexer.iindex(index);
+        const local_cindex = Indexer.cindex(index);
+        const local_sindex = Indexer.sindex(index);
+        const local_mindex = Indexer.mindex(index);
+        sync_iindex = sync_iindex.concat(local_iindex);
+        sync_cindex = sync_cindex.concat(local_cindex);
+        sync_mindex = sync_mindex.concat(local_mindex);
+
+        const HEAD = await Indexer.quickCompleteGlobalScope(block, sync_currConf, sync_bindex, sync_iindex, sync_mindex, sync_cindex, {
+          getBlock: (number: number) => {
+            return Promise.resolve(sync_allBlocks[number]);
+          },
+          getBlockByBlockstamp: (blockstamp: string) => {
+            return Promise.resolve(sync_allBlocks[parseInt(blockstamp)]);
+          }
+        });
+        sync_bindex.push(HEAD);
+
+        // Remember expiration dates
+        for (const entry of index) {
+          if (entry.op === 'CREATE' && (entry.expires_on || entry.revokes_on)) {
+            sync_expires.push(entry.expires_on || entry.revokes_on);
+          }
+        }
+        sync_expires = _.uniq(sync_expires);
+
+        await this.blockchain.createNewcomers(local_iindex, this.dal, this.logger)
+
+        if (block.dividend
+          || block.joiners.length
+          || block.actives.length
+          || block.revoked.length
+          || block.excluded.length
+          || block.certifications.length
+          || block.transactions.length
+          || block.medianTime >= sync_nextExpiring) {
+          // logger.warn('>> Block#%s', block.number)
+
+          for (let i = 0; i < sync_expires.length; i++) {
+            let expire = sync_expires[i];
+            if (block.medianTime > expire) {
+              sync_expires.splice(i, 1);
+              i--;
+            }
+          }
+          let currentNextExpiring = sync_nextExpiring
+          sync_nextExpiring = sync_expires.reduce((max, value) => max ? Math.min(max, value) : value, sync_nextExpiring);
+          const nextExpiringChanged = currentNextExpiring !== sync_nextExpiring
+
+          // Fills in correctly the SINDEX
+          await Promise.all(_.where(sync_sindex.concat(local_sindex), { op: 'UPDATE' }).map(async (entry: any) => {
+            if (!entry.conditions) {
+              const src = await this.dal.sindexDAL.getSource(entry.identifier, entry.pos);
+              entry.conditions = src.conditions;
+            }
+          }))
+
+          // Flush the INDEX (not bindex, which is particular)
+          await this.dal.mindexDAL.insertBatch(sync_mindex);
+          await this.dal.iindexDAL.insertBatch(sync_iindex);
+          await this.dal.sindexDAL.insertBatch(sync_sindex);
+          await this.dal.cindexDAL.insertBatch(sync_cindex);
+          sync_mindex = [];
+          sync_iindex = [];
+          sync_cindex = [];
+          sync_sindex = local_sindex;
+
+          sync_sindex = sync_sindex.concat(await Indexer.ruleIndexGenDividend(HEAD, this.dal));
+          sync_sindex = sync_sindex.concat(await Indexer.ruleIndexGarbageSmallAccounts(HEAD, sync_sindex, sync_memoryDAL));
+          if (nextExpiringChanged) {
+            sync_cindex = sync_cindex.concat(await Indexer.ruleIndexGenCertificationExpiry(HEAD, this.dal));
+            sync_mindex = sync_mindex.concat(await Indexer.ruleIndexGenMembershipExpiry(HEAD, this.dal));
+            sync_iindex = sync_iindex.concat(await Indexer.ruleIndexGenExclusionByMembership(HEAD, sync_mindex, this.dal));
+            sync_iindex = sync_iindex.concat(await Indexer.ruleIndexGenExclusionByCertificatons(HEAD, sync_cindex, local_iindex, this.conf, this.dal));
+            sync_mindex = sync_mindex.concat(await Indexer.ruleIndexGenImplicitRevocation(HEAD, this.dal));
+          }
+          // Update balances with UD + local garbagings
+          await this.blockchain.updateWallets(sync_sindex, sync_memoryDAL)
+
+          // --> Update links
+          await this.dal.updateWotbLinks(local_cindex.concat(sync_cindex));
+
+          // Flush the INDEX again
+          await this.dal.mindexDAL.insertBatch(sync_mindex);
+          await this.dal.iindexDAL.insertBatch(sync_iindex);
+          await this.dal.sindexDAL.insertBatch(sync_sindex);
+          await this.dal.cindexDAL.insertBatch(sync_cindex);
+          sync_mindex = [];
+          sync_iindex = [];
+          sync_cindex = [];
+          sync_sindex = [];
+
+          // Create/Update nodes in wotb
+          await this.blockchain.updateMembers(block, this.dal)
+        }
+
+        // Trim the bindex
+        sync_bindexSize = [
+          block.issuersCount,
+          block.issuersFrame,
+          this.conf.medianTimeBlocks,
+          this.conf.dtDiffEval,
+          blocks.length
+        ].reduce((max, value) => {
+          return Math.max(max, value);
+        }, 0);
+
+        if (sync_bindexSize && sync_bindex.length >= 2 * sync_bindexSize) {
+          // We trim it, not necessary to store it all (we already store the full blocks)
+          sync_bindex.splice(0, sync_bindexSize);
+
+          // Process triming continuously to avoid super long ending of sync
+          await this.dal.trimIndexes(sync_bindex[0].number);
+        }
+      } else {
+
+        if (blocksToSave.length) {
+          await this.saveBlocksInMainBranch(blocksToSave);
+        }
+        blocksToSave = [];
+
+        // Save the INDEX
+        await this.dal.bindexDAL.insertBatch(sync_bindex);
+        await this.dal.mindexDAL.insertBatch(sync_mindex);
+        await this.dal.iindexDAL.insertBatch(sync_iindex);
+        await this.dal.sindexDAL.insertBatch(sync_sindex);
+        await this.dal.cindexDAL.insertBatch(sync_cindex);
+
+        // Save the intermediary table of wallets
+        const conditions = _.keys(sync_memoryWallets)
+        const nonEmptyKeys = _.filter(conditions, (k: any) => sync_memoryWallets[k] && sync_memoryWallets[k].balance > 0)
+        const walletsToRecord = nonEmptyKeys.map((k: any) => sync_memoryWallets[k])
+        await this.dal.walletDAL.insertBatch(walletsToRecord)
+
+        // Last block: cautious mode to trigger all the INDEX expiry mechanisms
+        const { index, HEAD } = await this.blockchain.checkBlock(dto, constants.WITH_SIGNATURES_AND_POW, this.conf, this.dal)
+        await this.blockchain.pushTheBlock(dto, index, HEAD, this.conf, this.dal, this.logger)
+
+        // Clean temporary variables
+        sync_bindex = [];
+        sync_iindex = [];
+        sync_mindex = [];
+        sync_cindex = [];
+        sync_sindex = [];
+        sync_bindexSize = 0;
+        sync_allBlocks = [];
+        sync_expires = [];
+        sync_nextExpiring = 0;
+        // sync_currConf = {};
+      }
+    }
+    if (blocksToSave.length) {
+      await this.saveBlocksInMainBranch(blocksToSave);
+    }
+  }
+}
diff --git a/app/lib/computation/blockchainContext.js b/app/lib/computation/blockchainContext.js
deleted file mode 100644
index 03c554480..000000000
--- a/app/lib/computation/blockchainContext.js
+++ /dev/null
@@ -1,145 +0,0 @@
-"use strict";
-const _               = require('underscore');
-const co              = require('co');
-const indexer         = require('../indexer');
-const constants       = require('../constants');
-const Block           = require('../entity/block');
-
-module.exports = () => { return new BlockchainContext() };
-
-function BlockchainContext() {
-
-  const that = this;
-  let conf, dal, logger, blockchain, quickSynchronizer
-
-  /**
-   * The virtual next HEAD. Computed each time a new block is added, because a lot of HEAD variables are deterministic
-   * and can be computed one, just after a block is added for later controls.
-   */
-  let vHEAD;
-
-  /**
-   * The currently written HEAD, aka. HEAD_1 relatively to incoming HEAD.
-   */
-  let vHEAD_1;
-
-  let HEADrefreshed = Promise.resolve();
-
-  /**
-   * Refresh the virtual HEAD value for determined variables of the next coming block, avoiding to recompute them
-   * each time a new block arrives to check if the values are correct. We can know and store them early on, in vHEAD.
-   */
-  function refreshHead() {
-    HEADrefreshed = co(function*() {
-      vHEAD_1 = yield dal.head(1);
-      // We suppose next block will have same version #, and no particular data in the block (empty index)
-      let block;
-      // But if no HEAD_1 exist, we must initialize a block with default values
-      if (!vHEAD_1) {
-        block = {
-          version: constants.BLOCK_GENERATED_VERSION,
-          time: Math.round(Date.now() / 1000),
-          powMin: conf.powMin || 0,
-          powZeros: 0,
-          powRemainder: 0,
-          avgBlockSize: 0
-        };
-      } else {
-        block = { version: vHEAD_1.version };
-      }
-      vHEAD = yield indexer.completeGlobalScope(Block.statics.fromJSON(block), conf, [], dal);
-    });
-    return HEADrefreshed;
-  }
-
-  /**
-   * Gets a copy of vHEAD, extended with some extra properties.
-   * @param props The extra properties to add.
-   */
-  this.getvHeadCopy = (props) => co(function*() {
-    if (!vHEAD) {
-      yield refreshHead();
-    }
-    const copy = {};
-    const keys = Object.keys(vHEAD);
-    for (const k of keys) {
-      copy[k] = vHEAD[k];
-    }
-    _.extend(copy, props);
-    return copy;
-  });
-
-  /**
-   * Get currently written HEAD.
-   */
-  this.getvHEAD_1 = () => co(function*() {
-    if (!vHEAD) {
-      yield refreshHead();
-    }
-    return vHEAD_1;
-  });
-
-  /**
-   * Utility method: gives the personalized difficulty level of a given issuer for next block.
-   * @param issuer The issuer we want to get the difficulty level.
-   */
-  this.getIssuerPersonalizedDifficulty = (issuer) => co(function *() {
-    const local_vHEAD = yield that.getvHeadCopy({ issuer });
-    yield indexer.preparePersonalizedPoW(local_vHEAD, vHEAD_1, dal.range, conf);
-    return local_vHEAD.issuerDiff;
-  });
-
-  this.setConfDAL = (newConf, newDAL, theBlockchain, theQuickSynchronizer) => {
-    dal = newDAL;
-    conf = newConf;
-    blockchain = theBlockchain
-    quickSynchronizer = theQuickSynchronizer
-    logger = require('../logger')(dal.profile);
-  };
-
-  this.checkBlock = (block, withPoWAndSignature) => blockchain.checkBlock(block, withPoWAndSignature, conf, dal)
-
-  this.addBlock = (obj, index, HEAD) => co(function*() {
-    const block = yield blockchain.pushTheBlock(obj, index, HEAD, conf, dal, logger)
-    vHEAD_1 = vHEAD = HEADrefreshed = null
-    return block
-  })
-
-  this.addSideBlock = (obj) => blockchain.pushSideBlock(obj, dal, logger)
-
-  this.revertCurrentBlock = () => co(function *() {
-    const head_1 = yield dal.bindexDAL.head(1);
-    logger.debug('Reverting block #%s...', head_1.number);
-    const res = yield blockchain.revertBlock(head_1.number, head_1.hash, dal)
-    logger.debug('Reverted block #%s', head_1.number);
-    // Invalidates the head, since it has changed.
-    yield refreshHead();
-    return res;
-  });
-
-  this.applyNextAvailableFork = () => co(function *() {
-    const current = yield that.current();
-    logger.debug('Find next potential block #%s...', current.number + 1);
-    const forks = yield dal.getForkBlocksFollowing(current);
-    if (!forks.length) {
-      throw constants.ERRORS.NO_POTENTIAL_FORK_AS_NEXT;
-    }
-    const block = forks[0];
-    const { index, HEAD } = yield that.checkBlock(block, constants.WITH_SIGNATURES_AND_POW);
-    yield that.addBlock(block, index, HEAD);
-    logger.debug('Applied block #%s', block.number);
-  });
-
-  this.current = () => dal.getCurrentBlockOrNull();
-
-  this.checkHaveEnoughLinks = (target, newLinks) => co(function*() {
-    const links = yield dal.getValidLinksTo(target);
-    let count = links.length;
-    if (newLinks[target] && newLinks[target].length)
-      count += newLinks[target].length;
-    if (count < conf.sigQty)
-      throw 'Key ' + target + ' does not have enough links (' + count + '/' + conf.sigQty + ')';
-  });
-
-  this.quickApplyBlocks = (blocks, to) => quickSynchronizer.quickApplyBlocks(blocks, to)
-}
diff --git a/app/lib/computation/quickSync.js b/app/lib/computation/quickSync.js
deleted file mode 100644
index 0af47eb25..000000000
--- a/app/lib/computation/quickSync.js
+++ /dev/null
@@ -1,265 +0,0 @@
-"use strict"
-
-const Q = require('q');
-const _ = require('underscore')
-const co = require('co')
-const indexer = require('../indexer')
-const constants = require('../constants')
-const Block = require('../entity/block')
-const Transaction = require('../entity/transaction')
-const DuniterBlockchain = require('../blockchain/DuniterBlockchain').DuniterBlockchain
-
-module.exports = (blockchain, conf, dal, logger) => {
-
-  let sync_bindex = [];
-  let sync_iindex = [];
-  let sync_mindex = [];
-  let sync_cindex = [];
-  let sync_sindex = [];
-  let sync_bindexSize = 0;
-  let sync_allBlocks = [];
-  let sync_expires = [];
-  let sync_nextExpiring = 0;
-  let sync_currConf = {};
-  const sync_memoryWallets = {}
-  const sync_memoryDAL = {
-    getWallet: (conditions) => Promise.resolve(sync_memoryWallets[conditions] || { conditions, balance: 0 }),
-    saveWallet: (wallet) => co(function*() {
-      // Make a copy
-      sync_memoryWallets[wallet.conditions] = {
-        conditions: wallet.conditions,
-        balance: wallet.balance
-      }
-    })
-  }
-
-  const saveBlocksInMainBranch = (blocks) => co(function *() {
-    // VERY FIRST: parameters, otherwise we compute wrong variables such as UDTime
-    if (blocks[0].number == 0) {
-      yield blockchain.saveParametersForRoot(blocks[0], conf, dal)
-    }
-    // Helper to retrieve a block with local cache
-    const getBlock = (number) => {
-      const firstLocalNumber = blocks[0].number;
-      if (number >= firstLocalNumber) {
-        let offset = number - firstLocalNumber;
-        return Q(blocks[offset]);
-      }
-      return dal.getBlock(number);
-    };
-    const getBlockByNumberAndHash = (number, hash) => co(function*() {
-      const block = yield getBlock(number);
-      if (!block || block.hash != hash) {
-        throw 'Block #' + [number, hash].join('-') + ' not found neither in DB nor in applying blocks';
-      }
-      return block;
-    });
-    for (const block of blocks) {
-      block.fork = false;
-    }
-    // Transactions recording
-    yield updateTransactionsForBlocks(blocks, getBlockByNumberAndHash);
-    yield dal.blockDAL.saveBunch(blocks);
-    yield DuniterBlockchain.pushStatsForBlocks(blocks, dal);
-  });
-
-  function updateTransactionsForBlocks(blocks, getBlockByNumberAndHash) {
-    return co(function *() {
-      let txs = [];
-      for (const block of blocks) {
-        const newOnes = [];
-        for (const tx of block.transactions) {
-          _.extend(tx, {
-            block_number: block.number,
-            time: block.medianTime,
-            currency: block.currency,
-            written: true,
-            removed: false
-          });
-          const sp = tx.blockstamp.split('-');
-          tx.blockstampTime = (yield getBlockByNumberAndHash(sp[0], sp[1])).medianTime;
-          const txEntity = new Transaction(tx);
-          txEntity.computeAllHashes();
-          newOnes.push(txEntity);
-        }
-        txs = txs.concat(newOnes);
-      }
-      return dal.updateTransactions(txs);
-    })
-  }
-
-  const quickApplyBlocks = (blocks, to) => co(function*() {
-
-    sync_memoryDAL.sindexDAL = { getAvailableForConditions: dal.sindexDAL.getAvailableForConditions }
-    let blocksToSave = [];
-
-    for (const block of blocks) {
-      sync_allBlocks.push(block);
-
-      if (block.number == 0) {
-        sync_currConf = Block.statics.getConf(block);
-      }
-
-      if (block.number != to) {
-        blocksToSave.push(block);
-        const index = indexer.localIndex(block, sync_currConf);
-        const local_iindex = indexer.iindex(index);
-        const local_cindex = indexer.cindex(index);
-        const local_sindex = indexer.sindex(index);
-        const local_mindex = indexer.mindex(index);
-        sync_iindex = sync_iindex.concat(local_iindex);
-        sync_cindex = sync_cindex.concat(local_cindex);
-        sync_mindex = sync_mindex.concat(local_mindex);
-
-        const HEAD = yield indexer.quickCompleteGlobalScope(block, sync_currConf, sync_bindex, sync_iindex, sync_mindex, sync_cindex, {
-          getBlock: (number) => {
-            return Promise.resolve(sync_allBlocks[number]);
-          },
-          getBlockByBlockstamp: (blockstamp) => {
-            return Promise.resolve(sync_allBlocks[parseInt(blockstamp)]);
-          }
-        });
-        sync_bindex.push(HEAD);
-
-        // Remember expiration dates
-        for (const entry of index) {
-          if (entry.op === 'CREATE' && (entry.expires_on || entry.revokes_on)) {
-            sync_expires.push(entry.expires_on || entry.revokes_on);
-          }
-        }
-        sync_expires = _.uniq(sync_expires);
-
-        yield blockchain.createNewcomers(local_iindex, dal, logger)
-
-        if (block.dividend
-          || block.joiners.length
-          || block.actives.length
-          || block.revoked.length
-          || block.excluded.length
-          || block.certifications.length
-          || block.transactions.length
-          || block.medianTime >= sync_nextExpiring) {
-          // logger.warn('>> Block#%s', block.number)
-
-          for (let i = 0; i < sync_expires.length; i++) {
-            let expire = sync_expires[i];
-            if (block.medianTime > expire) {
-              sync_expires.splice(i, 1);
-              i--;
-            }
-          }
-          let currentNextExpiring = sync_nextExpiring
-          sync_nextExpiring = sync_expires.reduce((max, value) => max ? Math.min(max, value) : value, sync_nextExpiring);
-          const nextExpiringChanged = currentNextExpiring !== sync_nextExpiring
-
-          // Fills in correctly the SINDEX
-          yield _.where(sync_sindex.concat(local_sindex), { op: 'UPDATE' }).map((entry) => co(function*() {
-            if (!entry.conditions) {
-              const src = yield dal.sindexDAL.getSource(entry.identifier, entry.pos);
-              entry.conditions = src.conditions;
-            }
-          }))
-
-          // Flush the INDEX (not bindex, which is particular)
-          yield dal.mindexDAL.insertBatch(sync_mindex);
-          yield dal.iindexDAL.insertBatch(sync_iindex);
-          yield dal.sindexDAL.insertBatch(sync_sindex);
-          yield dal.cindexDAL.insertBatch(sync_cindex);
-          sync_mindex = [];
-          sync_iindex = [];
-          sync_cindex = [];
-          sync_sindex = local_sindex;
-
-          sync_sindex = sync_sindex.concat(yield indexer.ruleIndexGenDividend(HEAD, dal));
-          sync_sindex = sync_sindex.concat(yield indexer.ruleIndexGarbageSmallAccounts(HEAD, sync_sindex, sync_memoryDAL));
-          if (nextExpiringChanged) {
-            sync_cindex = sync_cindex.concat(yield indexer.ruleIndexGenCertificationExpiry(HEAD, dal));
-            sync_mindex = sync_mindex.concat(yield indexer.ruleIndexGenMembershipExpiry(HEAD, dal));
-            sync_iindex = sync_iindex.concat(yield indexer.ruleIndexGenExclusionByMembership(HEAD, sync_mindex, dal));
-            sync_iindex = sync_iindex.concat(yield indexer.ruleIndexGenExclusionByCertificatons(HEAD, sync_cindex, local_iindex, conf, dal));
-            sync_mindex = sync_mindex.concat(yield indexer.ruleIndexGenImplicitRevocation(HEAD, dal));
-          }
-          // Update balances with UD + local garbagings
-          yield blockchain.updateWallets(sync_sindex, sync_memoryDAL)
-
-          // --> Update links
-          yield dal.updateWotbLinks(local_cindex.concat(sync_cindex));
-
-          // Flush the INDEX again
-          yield dal.mindexDAL.insertBatch(sync_mindex);
-          yield dal.iindexDAL.insertBatch(sync_iindex);
-          yield dal.sindexDAL.insertBatch(sync_sindex);
-          yield dal.cindexDAL.insertBatch(sync_cindex);
-          sync_mindex = [];
-          sync_iindex = [];
-          sync_cindex = [];
-          sync_sindex = [];
-
-          // Create/Update nodes in wotb
-          yield blockchain.updateMembers(block, dal)
-        }
-
-        // Trim the bindex
-        sync_bindexSize = [
-          block.issuersCount,
-          block.issuersFrame,
-          conf.medianTimeBlocks,
-          conf.dtDiffEval,
-          blocks.length
-        ].reduce((max, value) => {
-          return Math.max(max, value);
-        }, 0);
-
-        if (sync_bindexSize && sync_bindex.length >= 2 * sync_bindexSize) {
-          // We trim it, not necessary to store it all (we already store the full blocks)
-          sync_bindex.splice(0, sync_bindexSize);
-
-          // Process triming continuously to avoid super long ending of sync
-          yield dal.trimIndexes(sync_bindex[0].number);
-        }
-      } else {
-
-        if (blocksToSave.length) {
-          yield saveBlocksInMainBranch(blocksToSave);
-        }
-        blocksToSave = [];
-
-        // Save the INDEX
-        yield dal.bindexDAL.insertBatch(sync_bindex);
-        yield dal.mindexDAL.insertBatch(sync_mindex);
-        yield dal.iindexDAL.insertBatch(sync_iindex);
-        yield dal.sindexDAL.insertBatch(sync_sindex);
-        yield dal.cindexDAL.insertBatch(sync_cindex);
-
-        // Save the intermediary table of wallets
-        const conditions = _.keys(sync_memoryWallets)
-        const nonEmptyKeys = _.filter(conditions, (k) => sync_memoryWallets[k] && sync_memoryWallets[k].balance > 0)
-        const walletsToRecord = nonEmptyKeys.map((k) => sync_memoryWallets[k])
-        yield dal.walletDAL.insertBatch(walletsToRecord)
-
-        // Last block: cautious mode to trigger all the INDEX expiry mechanisms
-        const { index, HEAD } = yield blockchain.checkBlock(block, constants.WITH_SIGNATURES_AND_POW, conf, dal)
-        yield blockchain.pushTheBlock(block, index, HEAD, conf, dal, logger)
-
-        // Clean temporary variables
-        sync_bindex = [];
-        sync_iindex = [];
-        sync_mindex = [];
-        sync_cindex = [];
-        sync_sindex = [];
-        sync_bindexSize = 0;
-        sync_allBlocks = [];
-        sync_expires = [];
-        sync_nextExpiring = 0;
-        sync_currConf = {};
-      }
-    }
-    if (blocksToSave.length) {
-      yield saveBlocksInMainBranch(blocksToSave);
-    }
-  })
-
-  return {
-    saveBlocksInMainBranch, quickApplyBlocks
-  }
-}
diff --git a/app/lib/dal/fileDAL.js b/app/lib/dal/fileDAL.js
index 9886dbb14..ad57c658c 100644
--- a/app/lib/dal/fileDAL.js
+++ b/app/lib/dal/fileDAL.js
@@ -3,7 +3,7 @@ const Q       = require('q');
 const co      = require('co');
 const _       = require('underscore');
 const common = require('duniter-common');
-const indexer = require('../indexer');
+const indexer = require('../indexer').Indexer
 const logger = require('../logger')('filedal');
 const Configuration = require('../entity/configuration');
 const Merkle = require('../entity/merkle');
diff --git a/app/lib/dal/sqliteDAL/AbstractIndex.js b/app/lib/dal/sqliteDAL/AbstractIndex.js
index 0187fc266..1078a8257 100644
--- a/app/lib/dal/sqliteDAL/AbstractIndex.js
+++ b/app/lib/dal/sqliteDAL/AbstractIndex.js
@@ -4,7 +4,7 @@
 
 const _ = require('underscore');
 const co = require('co');
-const indexer = require('../../indexer');
+const indexer = require('../../indexer').Indexer
 
 module.exports = AbstractIndex;
 
diff --git a/app/lib/dal/sqliteDAL/index/CIndexDAL.js b/app/lib/dal/sqliteDAL/index/CIndexDAL.js
index 37d2de859..dde0e9394 100644
--- a/app/lib/dal/sqliteDAL/index/CIndexDAL.js
+++ b/app/lib/dal/sqliteDAL/index/CIndexDAL.js
@@ -5,7 +5,7 @@
 const co = require('co');
 const constants = require('./../../../constants');
 const common = require('duniter-common');
-const indexer         = require('../../../indexer');
+const indexer         = require('../../../indexer').Indexer
 const AbstractSQLite = require('./../AbstractSQLite');
 const AbstractIndex = require('./../AbstractIndex');
 
diff --git a/app/lib/dal/sqliteDAL/index/IIndexDAL.js b/app/lib/dal/sqliteDAL/index/IIndexDAL.js
index 4dc35e6f0..4030b5905 100644
--- a/app/lib/dal/sqliteDAL/index/IIndexDAL.js
+++ b/app/lib/dal/sqliteDAL/index/IIndexDAL.js
@@ -4,7 +4,7 @@
 
 const co = require('co');
 const _ = require('underscore');
-const indexer         = require('../../../indexer');
+const indexer         = require('../../../indexer').Indexer
 const AbstractSQLite = require('./../AbstractSQLite');
 const AbstractIndex = require('./../AbstractIndex');
 
diff --git a/app/lib/dal/sqliteDAL/index/MIndexDAL.js b/app/lib/dal/sqliteDAL/index/MIndexDAL.js
index 572a9b327..77faa633d 100644
--- a/app/lib/dal/sqliteDAL/index/MIndexDAL.js
+++ b/app/lib/dal/sqliteDAL/index/MIndexDAL.js
@@ -3,7 +3,7 @@
  */
 
 const co = require('co');
-const indexer         = require('../../../indexer');
+const indexer         = require('../../../indexer').Indexer
 const AbstractSQLite = require('./../AbstractSQLite');
 const AbstractIndex = require('./../AbstractIndex');
 
diff --git a/app/lib/dal/sqliteDAL/index/SIndexDAL.js b/app/lib/dal/sqliteDAL/index/SIndexDAL.js
index 948eade98..f5e5e8413 100644
--- a/app/lib/dal/sqliteDAL/index/SIndexDAL.js
+++ b/app/lib/dal/sqliteDAL/index/SIndexDAL.js
@@ -5,7 +5,7 @@
 const _ = require('underscore');
 const co = require('co');
 const common = require('duniter-common');
-const indexer         = require('../../../indexer');
+const indexer         = require('../../../indexer').Indexer
 const constants = require('../../../constants');
 const AbstractSQLite = require('./../AbstractSQLite');
 const AbstractIndex = require('./../AbstractIndex');
diff --git a/app/lib/db/DBBlock.ts b/app/lib/db/DBBlock.ts
new file mode 100644
index 000000000..ad283135a
--- /dev/null
+++ b/app/lib/db/DBBlock.ts
@@ -0,0 +1,74 @@
+import {BlockDTO} from "../dto/BlockDTO"
+import {TransactionDTO} from "../dto/TransactionDTO"
+
+export class DBBlock {
+
+  version: number
+  number: number
+  currency: string
+  hash: string
+  inner_hash: string
+  signature: string
+  previousHash: string
+  issuer: string
+  previousIssuer: string
+  time: number
+  powMin: number
+  unitbase: number
+  membersCount: number
+  issuersCount: number
+  issuersFrame: number
+  issuersFrameVar: number
+  identities: string[]
+  joiners: string[]
+  actives: string[]
+  leavers: string[]
+  revoked: string[]
+  excluded: string[]
+  certifications: string[]
+  transactions: TransactionDTO[]
+  medianTime: number
+  nonce: number
+  fork: boolean
+  parameters: string
+  monetaryMass: number
+  dividend: number | null
+
+  constructor(
+  ) {
+  }
+
+  static fromBlockDTO(b:BlockDTO) {
+    const dbb = new DBBlock()
+    dbb.version = b.version
+    dbb.number = b.number
+    dbb.currency = b.currency
+    dbb.hash = b.hash
+    dbb.previousHash = b.previousHash
+    dbb.issuer = b.issuer
+    dbb.previousIssuer = b.previousIssuer
+    dbb.dividend = b.dividend
+    dbb.time = b.time
+    dbb.powMin = b.powMin
+    dbb.unitbase = b.unitbase
+    dbb.membersCount = b.membersCount
+    dbb.issuersCount = b.issuersCount
+    dbb.issuersFrame = b.issuersFrame
+    dbb.issuersFrameVar = b.issuersFrameVar
+    dbb.identities = b.identities
+    dbb.joiners = b.joiners
+    dbb.actives = b.actives
+    dbb.leavers = b.leavers
+    dbb.revoked = b.revoked
+    dbb.excluded = b.excluded
+    dbb.certifications = b.certifications
+    dbb.transactions = b.transactions
+    dbb.medianTime = b.medianTime
+    dbb.fork = b.fork
+    dbb.parameters = b.parameters
+    dbb.inner_hash = b.inner_hash
+    dbb.signature = b.signature
+    dbb.nonce = b.nonce
+    return dbb
+  }
+}
\ No newline at end of file
diff --git a/app/lib/db/DBHead.ts b/app/lib/db/DBHead.ts
new file mode 100644
index 000000000..2154b015f
--- /dev/null
+++ b/app/lib/db/DBHead.ts
@@ -0,0 +1,38 @@
+export class DBHead {
+
+  // TODO: some properties are not registered in the DB, we should create another class
+
+  version: number
+  currency: string | null
+  bsize: number
+  avgBlockSize: number
+  udTime: number
+  udReevalTime: number
+  massReeval: number
+  mass: number
+  hash: string
+  previousHash: string | null
+  previousIssuer: string | null
+  issuer: string
+  time: number
+  medianTime: number
+  number: number
+  powMin: number
+  diffNumber: number
+  issuersCount: number
+  issuersFrame: number
+  issuersFrameVar: number
+  dtDiffEval: number
+  issuerDiff: number
+  powZeros: number
+  powRemainder: number
+  speed: number
+  unitBase: number
+  membersCount: number
+  dividend: number
+  new_dividend: number | null
+  issuerIsMember: boolean
+
+  constructor(
+  ) {}
+}
\ No newline at end of file
diff --git a/app/lib/db/DBTransaction.ts b/app/lib/db/DBTransaction.ts
new file mode 100644
index 000000000..1a012e98d
--- /dev/null
+++ b/app/lib/db/DBTransaction.ts
@@ -0,0 +1,58 @@
+import {TransactionDTO} from "../dto/TransactionDTO"
+
+export class DBTransaction extends TransactionDTO {
+
+  constructor(
+    public version: number,
+    public currency: string,
+    public locktime: number,
+    public hash: string,
+    public blockstamp: string,
+    public issuers: string[],
+    public inputs: string[],
+    public outputs: string[],
+    public unlocks: string[],
+    public signatures: string[],
+    public comment: string,
+    public blockstampTime: number,
+    public written: boolean,
+    public removed: boolean,
+    public block_number: number,
+    public time: number,
+  ) {
+    super(
+      version,
+      currency,
+      locktime,
+      hash,
+      blockstamp,
+      issuers,
+      inputs,
+      outputs,
+      unlocks,
+      signatures,
+      comment
+    )
+  }
+
+  static fromTransactionDTO(dto:TransactionDTO, blockstampTime:number, written: boolean, removed: boolean, block_number:number, block_medianTime:number) {
+    return new DBTransaction(
+      dto.version,
+      dto.currency,
+      dto.locktime,
+      dto.hash,
+      dto.blockstamp,
+      dto.issuers,
+      dto.inputs,
+      dto.outputs,
+      dto.unlocks,
+      dto.signatures,
+      dto.comment || "",
+      blockstampTime,
+      written,
+      removed,
+      block_number,
+      block_medianTime
+    )
+  }
+}
\ No newline at end of file
diff --git a/app/lib/dto/BlockDTO.ts b/app/lib/dto/BlockDTO.ts
new file mode 100644
index 000000000..d966371fe
--- /dev/null
+++ b/app/lib/dto/BlockDTO.ts
@@ -0,0 +1,144 @@
+import {TransactionDTO} from "./TransactionDTO"
+export class BlockDTO {
+
+  version: number
+  number: number
+  currency: string
+  hash: string
+  inner_hash: string
+  previousHash: string
+  issuer: string
+  previousIssuer: string
+  dividend: number
+  time: number
+  powMin: number
+  unitbase: number
+  membersCount: number
+  issuersCount: number
+  issuersFrame: number
+  issuersFrameVar: number
+  identities: string[]
+  joiners: string[]
+  actives: string[]
+  leavers: string[]
+  revoked: string[]
+  excluded: string[]
+  certifications: string[]
+  transactions: TransactionDTO[]
+  medianTime: number
+  nonce: number
+  fork: boolean
+  parameters: string
+  signature: string
+
+  constructor(
+) {}
+
+  getInlineIdentity(pubkey:string): string | null {
+    let i = 0;
+    let found = null;
+    while (!found && i < this.identities.length) {
+      if (this.identities[i].match(new RegExp('^' + pubkey)))
+        found = this.identities[i];
+      i++;
+    }
+    return found;
+  }
+
+  getSignedPart() {
+    return "InnerHash: " + this.inner_hash + "\n" +
+      "Nonce: " + this.nonce + "\n"
+  }
+
+  getRawInnerPart() {
+    let raw = "";
+    raw += "Version: " + this.version + "\n";
+    raw += "Type: Block\n";
+    raw += "Currency: " + this.currency + "\n";
+    raw += "Number: " + this.number + "\n";
+    raw += "PoWMin: " + this.powMin + "\n";
+    raw += "Time: " + this.time + "\n";
+    raw += "MedianTime: " + this.medianTime + "\n";
+    if (this.dividend)
+      raw += "UniversalDividend: " + this.dividend + "\n";
+    raw += "UnitBase: " + this.unitbase + "\n";
+    raw += "Issuer: " + this.issuer + "\n";
+    raw += "IssuersFrame: " + this.issuersFrame + "\n";
+    raw += "IssuersFrameVar: " + this.issuersFrameVar + "\n";
+    raw += "DifferentIssuersCount: " + this.issuersCount + "\n";
+    if(this.previousHash)
+      raw += "PreviousHash: " + this.previousHash + "\n";
+    if(this.previousIssuer)
+      raw += "PreviousIssuer: " + this.previousIssuer + "\n";
+    if(this.parameters)
+      raw += "Parameters: " + this.parameters + "\n";
+    raw += "MembersCount: " + this.membersCount + "\n";
+    raw += "Identities:\n";
+    for (const idty of (this.identities || [])){
+      raw += idty + "\n";
+    }
+    raw += "Joiners:\n";
+    for (const joiner of (this.joiners || [])){
+      raw += joiner + "\n";
+    }
+    raw += "Actives:\n";
+    for (const active of (this.actives || [])){
+      raw += active + "\n";
+    }
+    raw += "Leavers:\n";
+    for (const leaver of (this.leavers || [])){
+      raw += leaver + "\n";
+    }
+    raw += "Revoked:\n";
+    for (const revoked of (this.revoked || [])){
+      raw += revoked + "\n";
+    }
+    raw += "Excluded:\n";
+    for (const excluded of (this.excluded || [])){
+      raw += excluded + "\n";
+    }
+    raw += "Certifications:\n";
+    for (const cert of (this.certifications || [])){
+      raw += cert + "\n";
+    }
+    raw += "Transactions:\n";
+    for (const tx of (this.transactions || [])){
+      raw += tx.getCompactVersion();
+    }
+    return raw
+  }
+
+  static fromJSONObject(obj:any) {
+    const dto = new BlockDTO()
+    dto.version = parseInt(obj.version)
+    dto.number = parseInt(obj.number)
+    dto.currency = obj.currency
+    dto.hash = obj.hash
+    dto.inner_hash = obj.inner_hash
+    dto.previousHash = obj.previousHash
+    dto.issuer = obj.issuer
+    dto.previousIssuer = obj.previousIssuer
+    dto.dividend = obj.dividend || null
+    dto.time = parseInt(obj.time)
+    dto.powMin = parseInt(obj.powMin)
+    dto.unitbase = parseInt(obj.unitbase)
+    dto.membersCount = parseInt(obj.membersCount)
+    dto.issuersCount = parseInt(obj.issuersCount)
+    dto.issuersFrame = parseInt(obj.issuersFrame)
+    dto.issuersFrameVar = parseInt(obj.issuersFrameVar)
+    dto.identities = obj.identities
+    dto.joiners = obj.joiners
+    dto.actives = obj.actives
+    dto.leavers = obj.leavers
+    dto.revoked = obj.revoked
+    dto.excluded = obj.excluded
+    dto.certifications = obj.certifications
+    dto.transactions = obj.transactions.map(TransactionDTO.fromJSONObject)
+    dto.medianTime = parseInt(obj.medianTime)
+    dto.fork = !!obj.fork
+    dto.parameters = obj.parameters
+    dto.signature = obj.signature
+    dto.nonce = parseInt(obj.nonce)
+    return dto
+  }
+}
\ No newline at end of file
diff --git a/app/lib/dto/CertificationDTO.ts b/app/lib/dto/CertificationDTO.ts
new file mode 100644
index 000000000..aca3cea3f
--- /dev/null
+++ b/app/lib/dto/CertificationDTO.ts
@@ -0,0 +1,14 @@
+export class CertificationDTO {
+
+  constructor(
+    public pubkey: string,
+    public to: string,
+    public block_number: number,
+    public sig: string
+  ) {}
+
+  static fromInline(inline:string): CertificationDTO {
+    const [pubkey, to, block_number, sig]: string[] = inline.split(':')
+    return new CertificationDTO(pubkey, to, parseInt(block_number), sig)
+  }
+}
\ No newline at end of file
diff --git a/app/lib/dto/ConfDTO.ts b/app/lib/dto/ConfDTO.ts
new file mode 100644
index 000000000..66cfca0d7
--- /dev/null
+++ b/app/lib/dto/ConfDTO.ts
@@ -0,0 +1,35 @@
+export class ConfDTO {
+
+  constructor(
+    public currency: string,
+    public endpoints: string[],
+    public rmEndpoints: string[],
+    public upInterval: number,
+    public c: number,
+    public dt: number,
+    public dtReeval: number,
+    public dtDiffEval: number,
+    public ud0: number,
+    public udTime0: number,
+    public udReevalTime0: number,
+    public stepMax: number,
+    public sigPeriod: number,
+    public msPeriod: number,
+    public sigValidity: number,
+    public msValidity: number,
+    public sigQty: number,
+    public sigStock: number,
+    public xpercent: number,
+    public percentRot: number,
+    public powDelay: number,
+    public avgGenTime: number,
+    public medianTimeBlocks: number,
+    public httplogs: boolean,
+    public timeout: number,
+    public isolate: boolean,
+    public forksize: number,
+    public idtyWindow: number,
+    public msWindow: number,
+    public sigWindow: number,
+) {}
+}
\ No newline at end of file
diff --git a/app/lib/dto/IdentityDTO.ts b/app/lib/dto/IdentityDTO.ts
new file mode 100644
index 000000000..a74857523
--- /dev/null
+++ b/app/lib/dto/IdentityDTO.ts
@@ -0,0 +1,32 @@
+
+import {hashf} from "../common"
+
+export class IdentityDTO {
+
+  currency:string
+
+  constructor(
+    public pubkey: string,
+    public sig: string,
+    public buid: string,
+    public uid: string
+  ) {}
+
+  get hash() {
+    return this.getTargetHash()
+  }
+
+  private getTargetHash() {
+    return hashf(this.uid + this.buid + this.pubkey)
+  }
+
+  static fromInline(inline:string): IdentityDTO {
+    const [pubkey, sig, buid, uid] = inline.split(':')
+    return new IdentityDTO(
+      pubkey,
+      sig,
+      buid,
+      uid
+    )
+  }
+}
\ No newline at end of file
diff --git a/app/lib/dto/RevocationDTO.ts b/app/lib/dto/RevocationDTO.ts
new file mode 100644
index 000000000..be0be61b1
--- /dev/null
+++ b/app/lib/dto/RevocationDTO.ts
@@ -0,0 +1,12 @@
+export class RevocationDTO {
+
+  constructor(
+    public pubkey: string,
+    public sig: string
+  ) {}
+
+  static fromInline(inline:string): RevocationDTO {
+    const [pubkey, sig] = inline.split(':')
+    return new RevocationDTO(pubkey, sig)
+  }
+}
\ No newline at end of file
diff --git a/app/lib/dto/TransactionDTO.ts b/app/lib/dto/TransactionDTO.ts
new file mode 100644
index 000000000..2bd4ea0d2
--- /dev/null
+++ b/app/lib/dto/TransactionDTO.ts
@@ -0,0 +1,150 @@
+import {hashf} from "../common"
+
+export class InputDTO {
+  constructor(
+    public amount: number,
+    public base: number,
+    public type: string,
+    public identifier: string,
+    public pos: number,
+    public raw: string
+  ) {}
+}
+
+export class OutputDTO {
+  constructor(
+    public amount: number,
+    public base: number,
+    public conditions: string,
+    public raw: string
+  ) {}
+}
+
+export class TransactionDTO {
+
+  constructor(
+    public version: number,
+    public currency: string,
+    public locktime: number,
+    public hash: string,
+    public blockstamp: string,
+    public issuers: string[],
+    public inputs: string[],
+    public outputs: string[],
+    public unlocks: string[],
+    public signatures: string[],
+    public comment?: string
+  ) {
+    // Compute the hash if not given
+    if (!hash) {
+      this.hash = this.getHash()
+    }
+  }
+
+  getHash() {
+    const raw = TransactionDTO.toRAW(this)
+    return hashf(raw)
+  }
+
+  getRawTxNoSig() {
+    return TransactionDTO.toRAW(this, true)
+  }
+
+  inputsAsObjects(): InputDTO[] {
+    return this.inputs.map(input => {
+      const [amount, base, type, identifier, pos] = input.split(':')
+      return new InputDTO(
+        parseInt(amount),
+        parseInt(base),
+        type,
+        identifier,
+        parseInt(pos),
+        input
+      )
+    })
+  }
+
+  outputsAsObjects(): OutputDTO[] {
+    return this.outputs.map(output => {
+      const [amount, base, conditions] = output.split(':')
+      return new OutputDTO(
+        parseInt(amount),
+        parseInt(base),
+        conditions,
+        output
+      )
+    })
+  }
+
+  getCompactVersion() {
+    let issuers = this.issuers;
+    let raw = ["TX", this.version, issuers.length, this.inputs.length, this.unlocks.length, this.outputs.length, this.comment ? 1 : 0, this.locktime || 0].join(':') + '\n';
+    raw += this.blockstamp + "\n";
+    (issuers || []).forEach((issuer) => {
+      raw += issuer + '\n';
+    });
+    (this.inputs || []).forEach((input) => {
+      raw += input + '\n';
+    });
+    (this.unlocks || []).forEach((input) => {
+      raw += input + '\n';
+    });
+    (this.outputs || []).forEach((output) => {
+      raw += output + '\n';
+    });
+    if (this.comment)
+      raw += this.comment + '\n';
+    (this.signatures || []).forEach((signature) => {
+      raw += signature + '\n'
+    })
+    return raw
+  }
+
+  static fromJSONObject(obj:any) {
+    return new TransactionDTO(
+      obj.version,
+      obj.currency,
+      obj.locktime,
+      obj.hash,
+      obj.blockstamp,
+      obj.issuers,
+      obj.inputs,
+      obj.outputs,
+      obj.unlocks,
+      obj.signatures,
+      obj.comment
+    )
+  }
+
+  static toRAW(json:TransactionDTO, noSig = false) {
+    let raw = ""
+    raw += "Version: " + (json.version) + "\n"
+    raw += "Type: Transaction\n"
+    raw += "Currency: " + json.currency + "\n"
+    raw += "Blockstamp: " + json.blockstamp + "\n"
+    raw += "Locktime: " + json.locktime + "\n"
+    raw += "Issuers:\n";
+    (json.issuers || []).forEach((issuer) => {
+      raw += issuer + '\n'
+    })
+    raw += "Inputs:\n";
+    (json.inputs || []).forEach((input) => {
+      raw += input + '\n'
+    })
+    raw += "Unlocks:\n";
+    (json.unlocks || []).forEach((unlock) => {
+      raw += unlock + '\n'
+    })
+    raw += "Outputs:\n";
+    (json.outputs  || []).forEach((output) => {
+      raw += output + '\n'
+    })
+    raw += "Comment: " + (json.comment || "") + "\n";
+    if (!noSig) {
+      (json.signatures || []).forEach((signature) => {
+        raw += signature + '\n'
+      })
+    }
+    return raw
+  }
+}
\ No newline at end of file
diff --git a/app/lib/indexer.js b/app/lib/indexer.ts
similarity index 51%
rename from app/lib/indexer.js
rename to app/lib/indexer.ts
index eec10464e..bed96bc9b 100644
--- a/app/lib/indexer.js
+++ b/app/lib/indexer.ts
@@ -1,4 +1,11 @@
 "use strict";
+import {BlockDTO} from "./dto/BlockDTO"
+import {ConfDTO} from "./dto/ConfDTO"
+import {IdentityDTO} from "./dto/IdentityDTO";
+import {RevocationDTO} from "./dto/RevocationDTO"
+import {CertificationDTO} from "./dto/CertificationDTO"
+import {OutputDTO, TransactionDTO} from "./dto/TransactionDTO"
+import {DBHead} from "./db/DBHead"
 
 const co              = require('co');
 const _               = require('underscore');
@@ -9,14 +16,119 @@ const rawer           = common.rawer
 const unlock          = common.txunlock
 const keyring         = common.keyring
 const Block           = common.document.Block
-const Identity        = common.document.Identity
-const Certification   = common.document.Certification
 const Membership      = common.document.Membership
-const Transaction     = common.document.Transaction
 
-const indexer = module.exports = {
+export interface IndexEntry {
+  index: string,
+  op: string,
+  writtenOn: number,
+  written_on: string,
+}
+
+export interface MindexEntry extends IndexEntry {
+  pub: string,
+  created_on: string,
+  type: string | null,
+  expires_on: number | null,
+  expired_on: number | null,
+  revocation: string | null,
+  revokes_on: number | null,
+  chainable_on: number | null,
+  revoked_on: string | null,
+  leaving: boolean | null,
+  age: number,
+  isBeingRevoked?: boolean,
+  unchainables: number,
+  numberFollowing?: boolean,
+  distanceOK?: boolean,
+  onRevoked?: boolean,
+  joinsTwice?: boolean,
+  enoughCerts?: boolean,
+  leaverIsMember?: boolean,
+  activeIsMember?: boolean,
+  revokedIsMember?: boolean,
+  alreadyRevoked?: boolean,
+  revocationSigOK?: boolean,
+}
+
+export interface IindexEntry extends IndexEntry {
+  uid: string | null,
+  pub: string,
+  hash: string | null,
+  sig: string | null,
+  created_on: string | null,
+  member: boolean,
+  wasMember: boolean | null,
+  kick: boolean | null,
+  wid: number | null,
+  age: number,
+  pubUnique?: boolean,
+  excludedIsMember?: boolean,
+  isBeingKicked?: boolean,
+  uidUnique?: boolean,
+  hasToBeExcluded?: boolean,
+  wotb_id?: number,
+}
+
+export interface CindexEntry extends IndexEntry {
+  issuer: string,
+  receiver: string,
+  created_on: number,
+  sig: string,
+  chainable_on: number,
+  expires_on: number,
+  expired_on: number,
+  from_wid: null, // <-These 2 fields are useless
+  to_wid: null,    // <-'
+  unchainables: number,
+  age: number,
+  stock: number,
+  fromMember?: boolean,
+  toMember?: boolean,
+  toNewcomer?: boolean,
+  toLeaver?: boolean,
+  isReplay?: boolean,
+  sigOK?: boolean,
+}
+
+export interface SindexEntry extends IndexEntry {
+  tx: string | null,
+  identifier: string,
+  pos: number,
+  created_on: string | null,
+  written_time: number,
+  locktime: number,
+  unlock: string | null,
+  amount: number,
+  base: number,
+  conditions: string,
+  consumed: boolean,
+  txObj: TransactionDTO,
+  age: number,
+  available?: boolean,
+  isLocked?: boolean,
+  isTimeLocked?: boolean,
+}
+
+interface Ranger {
+  (n:number, m:number, prop?:string): Promise<DBHead[]>
+}
 
-  localIndex: (block, conf) => {
+function pushIindex(index: any[], entry: IindexEntry): void {
+  index.push(entry)
+}
+
+function pushMindex(index: any[], entry: MindexEntry): void {
+  index.push(entry)
+}
+
+function pushCindex(index: any[], entry: CindexEntry): void {
+  index.push(entry)
+}
+
+export class Indexer {
+
+  static localIndex(block:BlockDTO, conf:ConfDTO): IndexEntry[] {
 
     /********************
      * GENERAL BEHAVIOR
@@ -34,15 +146,15 @@ const indexer = module.exports = {
      * * for each tx input:  1 index (1 sindex UPDATE)
      */
 
-    const index = [];
+    const index: IndexEntry[] = [];
 
     /***************************
      * IDENTITIES INDEX (IINDEX)
      **************************/
     for (const identity of block.identities) {
-      const idty = Identity.fromInline(identity);
+      const idty = IdentityDTO.fromInline(identity);
       // Computes the hash if not done yet
-      index.push({
+      pushIindex(index, {
         index: constants.I_INDEX,
         op: constants.IDX_CREATE,
         uid: idty.uid,
@@ -52,11 +164,12 @@ const indexer = module.exports = {
         created_on: idty.buid,
         written_on: [block.number, block.hash].join('-'),
         writtenOn: block.number,
+        age: 0,
         member: true,
         wasMember: true,
         kick: false,
         wid: null // wotb id
-      });
+      })
     }
 
     /****************************
@@ -65,118 +178,145 @@ const indexer = module.exports = {
     // Joiners (newcomer or join back)
     for (const inlineMS of block.joiners) {
       const ms = Membership.fromInline(inlineMS);
-      const matchesANewcomer = _.filter(index, (row) => row.index == constants.I_INDEX && row.pub == ms.issuer).length > 0;
+      const matchesANewcomer = _.filter(index, (row: IindexEntry) => row.index == constants.I_INDEX && row.pub == ms.issuer).length > 0;
       if (matchesANewcomer) {
         // Newcomer
-        index.push({
+        pushMindex(index, {
           index: constants.M_INDEX,
           op: constants.IDX_CREATE,
           pub: ms.issuer,
           created_on: [ms.number, ms.fpr].join('-'),
           written_on: [block.number, block.hash].join('-'),
           writtenOn: block.number,
+          age: 0,
+          unchainables: 0,
           type: 'JOIN',
           expires_on: conf.msValidity,
+          expired_on: null,
           revokes_on: conf.msValidity * constants.REVOCATION_FACTOR,
-          chainable_on: parseInt(block.medianTime) + conf.msPeriod,
+          revocation: null,
+          chainable_on: block.medianTime + conf.msPeriod,
           revoked_on: null,
           leaving: false
-        });
+        })
       } else {
         // Join back
-        index.push({
+        pushMindex(index, {
           index: constants.M_INDEX,
           op: constants.IDX_UPDATE,
           pub: ms.issuer,
           created_on: [ms.number, ms.fpr].join('-'),
           written_on: [block.number, block.hash].join('-'),
           writtenOn: block.number,
+          age: 0,
+          unchainables: 0,
           type: 'JOIN',
           expires_on: conf.msValidity,
+          expired_on: null,
           revokes_on: conf.msValidity * constants.REVOCATION_FACTOR,
-          chainable_on: parseInt(block.medianTime) + conf.msPeriod,
+          revocation: null,
+          chainable_on: block.medianTime + conf.msPeriod,
           revoked_on: null,
           leaving: null
-        });
-        index.push({
+        })
+        pushIindex(index, {
           index: constants.I_INDEX,
           op: constants.IDX_UPDATE,
           uid: null,
           pub: ms.issuer,
+          hash: null,
+          sig: null,
           created_on: null,
           written_on: [block.number, block.hash].join('-'),
           writtenOn: block.number,
+          age: 0,
           member: true,
           wasMember: null,
           kick: null,
           wid: null
-        });
+        })
       }
     }
     // Actives
     for (const inlineMS of block.actives) {
       const ms = Membership.fromInline(inlineMS);
       // Renew
-      index.push({
+      pushMindex(index, {
         index: constants.M_INDEX,
         op: constants.IDX_UPDATE,
         pub: ms.issuer,
         created_on: [ms.number, ms.fpr].join('-'),
         written_on: [block.number, block.hash].join('-'),
         writtenOn: block.number,
+        age: 0,
+        unchainables: 0,
         type: 'ACTIVE',
         expires_on: conf.msValidity,
+        expired_on: null,
         revokes_on: conf.msValidity * constants.REVOCATION_FACTOR,
-        chainable_on: parseInt(block.medianTime) + conf.msPeriod,
+        revocation: null,
+        chainable_on: block.medianTime + conf.msPeriod,
         revoked_on: null,
         leaving: null
-      });
+      })
     }
     // Leavers
     for (const inlineMS of block.leavers) {
       const ms = Membership.fromInline(inlineMS);
-      index.push({
+      pushMindex(index, {
         index: constants.M_INDEX,
         op: constants.IDX_UPDATE,
         pub: ms.issuer,
         created_on: [ms.number, ms.fpr].join('-'),
         written_on: [block.number, block.hash].join('-'),
         writtenOn: block.number,
+        age: 0,
+        unchainables: 0,
         type: 'LEAVE',
         expires_on: null,
+        expired_on: null,
         revokes_on: null,
-        chainable_on: parseInt(block.medianTime) + conf.msPeriod,
+        revocation: null,
+        chainable_on: block.medianTime + conf.msPeriod,
         revoked_on: null,
         leaving: true
-      });
+      })
     }
     // Revoked
     for (const inlineRevocation of block.revoked) {
-      const revocation = Identity.revocationFromInline(inlineRevocation);
-      index.push({
+      const revocation = RevocationDTO.fromInline(inlineRevocation)
+      pushMindex(index, {
         index: constants.M_INDEX,
         op: constants.IDX_UPDATE,
         pub: revocation.pubkey,
         created_on: [block.number, block.hash].join('-'),
         written_on: [block.number, block.hash].join('-'),
         writtenOn: block.number,
+        age: 0,
+        unchainables: 0,
+        type: null,
         expires_on: null,
+        expired_on: null,
         revokes_on: null,
-        revoked_on: [block.number, block.hash].join('-'),
         revocation: revocation.sig,
+        chainable_on: null,
+        revoked_on: [block.number, block.hash].join('-'),
         leaving: false
-      });
+      })
     }
     // Excluded
     for (const excluded of block.excluded) {
-      index.push({
+      pushIindex(index, {
         index: constants.I_INDEX,
         op: constants.IDX_UPDATE,
         uid: null,
         pub: excluded,
+        hash: null,
+        sig: null,
         created_on: null,
         written_on: [block.number, block.hash].join('-'),
         writtenOn: block.number,
+        age: 0,
         member: false,
         wasMember: null,
         kick: false,
@@ -188,8 +328,8 @@ const indexer = module.exports = {
      * CERTIFICATIONS INDEX (CINDEX)
      ******************************/
     for (const inlineCert of block.certifications) {
-      const cert = Certification.fromInline(inlineCert);
-      index.push({
+      const cert = CertificationDTO.fromInline(inlineCert);
+      pushCindex(index, {
         index: constants.C_INDEX,
         op: constants.IDX_CREATE,
         issuer: cert.pubkey,
@@ -197,129 +337,119 @@ const indexer = module.exports = {
         created_on: cert.block_number,
         written_on: [block.number, block.hash].join('-'),
         writtenOn: block.number,
+        age: 0,
+        stock: conf.sigStock,
+        unchainables: 0,
         sig: cert.sig,
-        chainable_on: parseInt(block.medianTime)  + conf.sigPeriod,
+        chainable_on: block.medianTime  + conf.sigPeriod,
         expires_on: conf.sigValidity,
         expired_on: 0,
         from_wid: null,
         to_wid: null
-      });
+      })
     }
 
-    return index.concat(module.exports.localSIndex(block));
-  },
+    return index.concat(Indexer.localSIndex(block));
+  }
 
-  localSIndex: (block) => {
+  static localSIndex(block:BlockDTO): SindexEntry[] {
     /*******************************
      * SOURCES INDEX (SINDEX)
      ******************************/
-    const index = [];
-    if (!block.transactions && block.getTransactions) {
-      const txs = block.getTransactions();
-      block.transactions = [];
-      for (const tx of txs) {
-        block.transactions.push({
-          version: tx.version,
-          comment: tx.comment,
-          issuers: tx.issuers,
-          signatures: tx.signatures,
-          inputs: tx.inputs.map((i) => i.raw),
-          outputs: tx.outputs.map((o) => o.raw)
-        });
-      }
-    }
-    for (const obj of block.transactions) {
-      obj.currency = block.currency || obj.currency;
-      const txObj = Transaction.fromJSON(obj);
-      const txHash = txObj.getHash(true);
+    const index: SindexEntry[] = [];
+    for (const tx of block.transactions) {
+      tx.currency = block.currency || tx.currency;
+      const txHash = tx.getHash()
       let k = 0;
-      for (const input of txObj.inputs) {
+      for (const input of tx.inputsAsObjects()) {
         index.push({
           index: constants.S_INDEX,
           op: constants.IDX_UPDATE,
           tx: txHash,
           identifier: input.identifier,
           pos: input.pos,
-          created_on: obj.blockstamp,
+          created_on: tx.blockstamp,
           written_on: [block.number, block.hash].join('-'),
           writtenOn: block.number,
+          age: 0,
           written_time: block.medianTime,
-          locktime: obj.locktime,
-          unlock: txObj.unlocks[k],
+          locktime: tx.locktime,
+          unlock: tx.unlocks[k],
           amount: input.amount,
           base: input.base,
-          conditions: null,
+          conditions: "", // Is overriden thereafter
           consumed: true,
-          txObj: txObj
+          txObj: tx
         });
         k++;
       }
 
       let i = 0;
-      for (const output of txObj.outputs) {
+      for (const output of tx.outputsAsObjects()) {
         index.push({
           index: constants.S_INDEX,
           op: constants.IDX_CREATE,
           tx: txHash,
           identifier: txHash,
           pos: i++,
+          created_on: null,
           written_on: [block.number, block.hash].join('-'),
           writtenOn: block.number,
+          age: 0,
           written_time: block.medianTime,
-          locktime: obj.locktime,
+          locktime: tx.locktime,
+          unlock: null,
           amount: output.amount,
           base: output.base,
           conditions: output.conditions,
           consumed: false,
-          txObj: obj
+          txObj: tx
         });
       }
     }
     return index;
-  },
+  }
 
-  quickCompleteGlobalScope: (block, conf, bindex, iindex, mindex, cindex, dal) => co(function*() {
+  static async quickCompleteGlobalScope(block: BlockDTO, conf: ConfDTO, bindex: DBHead[], iindex: IindexEntry[], mindex: MindexEntry[], cindex: CindexEntry[], dal: any) {
 
-    function range(start, end, property) {
-      return co(function*() {
-        let theRange;
-        end = Math.min(end, bindex.length);
-        if (start == 1) {
-          theRange = bindex.slice(-end);
-        } else {
-          theRange = bindex.slice(-end, -start + 1);
-        }
-        theRange.reverse();
-        if (property) {
-          // Filter on a particular property
-          return theRange.map((b) => b[property]);
-        } else {
-          return theRange;
-        }
-      });
+    function range(start: number, end: number, property = ""): any {
+      let theRange;
+      end = Math.min(end, bindex.length);
+      if (start == 1) {
+        theRange = bindex.slice(-end);
+      } else {
+        theRange = bindex.slice(-end, -start + 1);
+      }
+      theRange.reverse();
+      if (property) {
+        // Filter on a particular property
+        return theRange.map((b:any) => b[property]);
+      } else {
+        return theRange;
+      }
     }
 
-    function head(n) {
-      return co(function*() {
-        return (yield range(n, n))[0];
-      });
+    async function head(n:number) {
+      return range(n, n)[0];
     }
 
-    const HEAD = {
-      version: block.version,
-      currency: block.currency,
-      bsize: Block.getLen(block),
-      hash: Block.getHash(block),
-      issuer: block.issuer,
-      time: block.time,
-      medianTime: block.medianTime,
-      number: block.number,
-      powMin: block.powMin,
-      unitBase: block.unitbase,
-      membersCount: block.membersCount,
-      dividend: block.dividend
-    };
-    const HEAD_1 = yield head(1);
+    const HEAD = new DBHead()
+
+    HEAD.version = block.version
+    HEAD.currency = block.currency
+    HEAD.bsize = Block.getLen(block)
+    HEAD.hash = Block.getHash(block)
+    HEAD.issuer = block.issuer
+    HEAD.time = block.time
+    HEAD.medianTime = block.medianTime
+    HEAD.number = block.number
+    HEAD.powMin = block.powMin
+    HEAD.unitBase = block.unitbase
+    HEAD.membersCount = block.membersCount
+    HEAD.dividend = block.dividend
+    HEAD.new_dividend = null
+
+    const HEAD_1 = await head(1);
 
     if (HEAD.number == 0) {
       HEAD.dividend = conf.ud0;
@@ -331,72 +461,73 @@ const indexer = module.exports = {
     }
 
     // BR_G04
-    yield indexer.prepareIssuersCount(HEAD, range, HEAD_1);
+    await Indexer.prepareIssuersCount(HEAD, range, HEAD_1);
 
     // BR_G05
-    indexer.prepareIssuersFrame(HEAD, HEAD_1);
+    Indexer.prepareIssuersFrame(HEAD, HEAD_1);
 
     // BR_G06
-    indexer.prepareIssuersFrameVar(HEAD, HEAD_1);
+    Indexer.prepareIssuersFrameVar(HEAD, HEAD_1);
 
     // BR_G07
-    yield indexer.prepareAvgBlockSize(HEAD, range);
+    await Indexer.prepareAvgBlockSize(HEAD, range);
 
     // BR_G09
-    indexer.prepareDiffNumber(HEAD, HEAD_1, conf);
+    Indexer.prepareDiffNumber(HEAD, HEAD_1, conf)
 
     // BR_G11
-    indexer.prepareUDTime(HEAD, HEAD_1, conf);
+    Indexer.prepareUDTime(HEAD, HEAD_1, conf)
 
     // BR_G15
-    indexer.prepareMass(HEAD, HEAD_1);
+    Indexer.prepareMass(HEAD, HEAD_1);
 
     // BR_G16
-    yield indexer.prepareSpeed(HEAD, head, conf);
+    await Indexer.prepareSpeed(HEAD, head, conf)
 
     // BR_G19
-    yield indexer.prepareIdentitiesAge(iindex, HEAD, HEAD_1, conf, dal);
+    await Indexer.prepareIdentitiesAge(iindex, HEAD, HEAD_1, conf, dal);
 
     // BR_G22
-    yield indexer.prepareMembershipsAge(mindex, HEAD, HEAD_1, conf, dal);
+    await Indexer.prepareMembershipsAge(mindex, HEAD, HEAD_1, conf, dal);
 
     // BR_G37
-    yield indexer.prepareCertificationsAge(cindex, HEAD, HEAD_1, conf, dal);
+    await Indexer.prepareCertificationsAge(cindex, HEAD, HEAD_1, conf, dal);
 
     // BR_G104
-    yield indexer.ruleIndexCorrectMembershipExpiryDate(HEAD, mindex, dal);
+    await Indexer.ruleIndexCorrectMembershipExpiryDate(HEAD, mindex, dal);
 
     // BR_G105
-    yield indexer.ruleIndexCorrectCertificationExpiryDate(HEAD, cindex, dal);
+    await Indexer.ruleIndexCorrectCertificationExpiryDate(HEAD, cindex, dal);
 
     return HEAD;
-  }),
+  }
 
-  completeGlobalScope: (block, conf, index, dal) => co(function*() {
+  static async completeGlobalScope(block: BlockDTO, conf: ConfDTO, index: IndexEntry[], dal: any) {
 
-    const iindex = module.exports.iindex(index);
-    const mindex = module.exports.mindex(index);
-    const cindex = module.exports.cindex(index);
-    const sindex = module.exports.sindex(index);
+    const iindex = Indexer.iindex(index);
+    const mindex = Indexer.mindex(index);
+    const cindex = Indexer.cindex(index);
+    const sindex = Indexer.sindex(index);
 
     const range = dal.range;
     const head = dal.head;
 
-    const HEAD = {
-      version: block.version,
-      bsize: Block.getLen(block),
-      hash: Block.getHash(block),
-      issuer: block.issuer,
-      time: block.time,
-      powMin: block.powMin
-    };
-    const HEAD_1 = yield head(1);
+    const HEAD = new DBHead()
+
+    HEAD.version = block.version
+    HEAD.bsize = Block.getLen(block)
+    HEAD.hash = Block.getHash(block)
+    HEAD.issuer = block.issuer
+    HEAD.time = block.time
+    HEAD.powMin = block.powMin
+
+    const HEAD_1 = await head(1);
     if (HEAD_1) {
       HEAD_1.currency = conf.currency;
     }
 
     // BR_G01
-    indexer.prepareNumber(HEAD, HEAD_1);
+    Indexer.prepareNumber(HEAD, HEAD_1);
 
     // BR_G02
     if (HEAD.number > 0) {
@@ -421,44 +552,44 @@ const indexer = module.exports = {
 
     // BR_G03
     if (HEAD.number > 0) {
-      HEAD.issuerIsMember = reduce(yield dal.iindexDAL.reducable(HEAD.issuer)).member;
+      HEAD.issuerIsMember = reduce(await dal.iindexDAL.reducable(HEAD.issuer)).member;
     } else {
       HEAD.issuerIsMember = reduce(_.where(iindex, { pub: HEAD.issuer })).member;
     }
 
     // BR_G04
-    yield indexer.prepareIssuersCount(HEAD, range, HEAD_1);
+    await Indexer.prepareIssuersCount(HEAD, range, HEAD_1);
 
     // BR_G05
-    indexer.prepareIssuersFrame(HEAD, HEAD_1);
+    Indexer.prepareIssuersFrame(HEAD, HEAD_1);
 
     // BR_G06
-    indexer.prepareIssuersFrameVar(HEAD, HEAD_1);
+    Indexer.prepareIssuersFrameVar(HEAD, HEAD_1);
 
     // BR_G07
-    yield indexer.prepareAvgBlockSize(HEAD, range);
+    await Indexer.prepareAvgBlockSize(HEAD, range);
 
     // BR_G08
     if (HEAD.number > 0) {
-      HEAD.medianTime = Math.max(HEAD_1.medianTime, average(yield range(1, Math.min(conf.medianTimeBlocks, HEAD.number), 'time')));
+      HEAD.medianTime = Math.max(HEAD_1.medianTime, average(await range(1, Math.min(conf.medianTimeBlocks, HEAD.number), 'time')));
     } else {
       HEAD.medianTime = HEAD.time;
     }
 
     // BR_G09
-    indexer.prepareDiffNumber(HEAD, HEAD_1, conf);
+    Indexer.prepareDiffNumber(HEAD, HEAD_1, conf)
 
     // BR_G10
     if (HEAD.number == 0) {
-      HEAD.membersCount = count(_.filter(iindex, (entry) => entry.member === true));
+      HEAD.membersCount = count(_.filter(iindex, (entry:IindexEntry) => entry.member === true));
     } else {
       HEAD.membersCount = HEAD_1.membersCount
-        + count(_.filter(iindex, (entry) => entry.member === true))
-        - count(_.filter(iindex, (entry) => entry.member === false));
+        + count(_.filter(iindex, (entry:IindexEntry) => entry.member === true))
+        - count(_.filter(iindex, (entry:IindexEntry) => entry.member === false));
     }
 
     // BR_G11
-    indexer.prepareUDTime(HEAD, HEAD_1, conf);
+    Indexer.prepareUDTime(HEAD, HEAD_1, conf)
 
     // BR_G12
     if (HEAD.number == 0) {
@@ -468,16 +599,16 @@ const indexer = module.exports = {
     }
 
     // BR_G13
-    indexer.prepareDividend(HEAD, HEAD_1, conf);
+    Indexer.prepareDividend(HEAD, HEAD_1, conf)
 
     // BR_G14
-    indexer.prepareUnitBase(HEAD, HEAD_1, conf);
+    Indexer.prepareUnitBase(HEAD);
 
     // BR_G15
-    indexer.prepareMass(HEAD, HEAD_1);
+    Indexer.prepareMass(HEAD, HEAD_1);
 
     // BR_G16
-    yield indexer.prepareSpeed(HEAD, head, conf);
+    await Indexer.prepareSpeed(HEAD, head, conf)
 
     // BR_G17
     if (HEAD.number > 0) {
@@ -502,75 +633,73 @@ const indexer = module.exports = {
     }
 
     // BR_G18
-    yield indexer.preparePersonalizedPoW(HEAD, HEAD_1, range, conf);
+    await Indexer.preparePersonalizedPoW(HEAD, HEAD_1, range, conf)
 
     // BR_G19
-    yield indexer.prepareIdentitiesAge(iindex, HEAD, HEAD_1, conf, dal);
+    await Indexer.prepareIdentitiesAge(iindex, HEAD, HEAD_1, conf, dal);
 
     // BR_G20
-    yield iindex.map((ENTRY) => co(function*() {
+    await Promise.all(iindex.map(async (ENTRY: IindexEntry) => {
       if (ENTRY.op == constants.IDX_CREATE) {
-        ENTRY.uidUnique = count(yield dal.iindexDAL.sqlFind({ uid: ENTRY.uid })) == 0;
+        ENTRY.uidUnique = count(await dal.iindexDAL.sqlFind({ uid: ENTRY.uid })) == 0;
       } else {
         ENTRY.uidUnique = true;
       }
-    }));
+    }))
 
     // BR_G21
-    yield iindex.map((ENTRY) => co(function*() {
+    await Promise.all(iindex.map(async (ENTRY: IindexEntry) => {
       if (ENTRY.op == constants.IDX_CREATE) {
-        ENTRY.pubUnique = count(yield dal.iindexDAL.sqlFind({pub: ENTRY.pub})) == 0;
+        ENTRY.pubUnique = count(await dal.iindexDAL.sqlFind({pub: ENTRY.pub})) == 0;
       } else {
         ENTRY.pubUnique = true;
       }
-    }));
+    }))
 
     // BR_G33
-    yield iindex.map((ENTRY) => co(function*() {
+    await Promise.all(iindex.map(async (ENTRY: IindexEntry) => {
       if (ENTRY.member !== false) {
         ENTRY.excludedIsMember = true;
       } else {
-        ENTRY.excludedIsMember = reduce(yield dal.iindexDAL.reducable(ENTRY.pub)).member;
+        ENTRY.excludedIsMember = reduce(await dal.iindexDAL.reducable(ENTRY.pub)).member;
       }
-    }));
+    }))
 
     // BR_G34
-    yield mindex.map((ENTRY) => co(function*() {
+    mindex.map((ENTRY: MindexEntry) => {
       ENTRY.isBeingRevoked = !!ENTRY.revoked_on;
-    }));
+    })
 
     // BR_G107
     if (HEAD.number > 0) {
-      yield mindex.map((ENTRY) => co(function*() {
-        const rows = yield dal.mindexDAL.sqlFind({ pub: ENTRY.pub, chainable_on: { $gt: HEAD_1.medianTime }});
+      await Promise.all(mindex.map(async (ENTRY: MindexEntry) => {
+        const rows = await dal.mindexDAL.sqlFind({ pub: ENTRY.pub, chainable_on: { $gt: HEAD_1.medianTime }});
         // This rule will be enabled on
         if (HEAD.medianTime >= 1498860000) {
           ENTRY.unchainables = count(rows);
-        } else {
-          ENTRY.unchainables = []
         }
-      }));
+      }))
     }
 
     // BR_G35
-    yield iindex.map((ENTRY) => co(function*() {
-      ENTRY.isBeingKicked = ENTRY.member === false;
-    }));
+    await Promise.all(iindex.map(async (ENTRY: IindexEntry) => {
+      ENTRY.isBeingKicked = ENTRY.member === false
+    }))
 
     // BR_G36
-    yield iindex.map((ENTRY) => co(function*() {
-      const isMarkedAsToKick = reduce(yield dal.iindexDAL.reducable(ENTRY.pub)).kick;
-      const isBeingRevoked = count(_.filter(mindex, (m) => m.isBeingRevoked && m.pub == ENTRY.pub)) == 1;
+    await Promise.all(iindex.map(async (ENTRY: IindexEntry) => {
+      const isMarkedAsToKick = reduce(await dal.iindexDAL.reducable(ENTRY.pub)).kick;
+      const isBeingRevoked = count(_.filter(mindex, (m:MindexEntry) => m.isBeingRevoked && m.pub == ENTRY.pub)) == 1;
       ENTRY.hasToBeExcluded = isMarkedAsToKick || isBeingRevoked;
-    }));
+    }))
 
     // BR_G22
-    yield indexer.prepareMembershipsAge(mindex, HEAD, HEAD_1, conf, dal);
+    await Indexer.prepareMembershipsAge(mindex, HEAD, HEAD_1, conf, dal);
 
     // BR_G23
-    yield mindex.map((ENTRY) => co(function*() {
+    await Promise.all(mindex.map(async (ENTRY: MindexEntry) => {
       if (!ENTRY.revoked_on) {
-        const created_on = reduce(yield dal.mindexDAL.reducable(ENTRY.pub)).created_on;
+        const created_on = reduce(await dal.mindexDAL.reducable(ENTRY.pub)).created_on;
         if (created_on != null) {
           ENTRY.numberFollowing = number(ENTRY.created_on) > number(created_on);
         } else {
@@ -579,23 +708,23 @@ const indexer = module.exports = {
       } else {
         ENTRY.numberFollowing = true;
       }
-    }));
+    }))
 
     // BR_G24
     // Global testing, because of wotb
-    const oneIsOutdistanced = yield checkPeopleAreNotOudistanced(
-      _.filter(mindex, (entry) => !entry.revoked_on).map((entry) => entry.pub),
-      cindex.reduce((newLinks, c) => {
+    const oneIsOutdistanced = await checkPeopleAreNotOudistanced(
+      _.filter(mindex, (entry: MindexEntry) => !entry.revoked_on).map((entry: MindexEntry) => entry.pub),
+      cindex.reduce((newLinks:any, c: CindexEntry) => {
         newLinks[c.receiver] = newLinks[c.receiver] || [];
         newLinks[c.receiver].push(c.issuer);
         return newLinks;
       }, {}),
       // Newcomers
-      _.where(iindex, { op: constants.IDX_CREATE }).map((entry) => entry.pub),
+      _.where(iindex, { op: constants.IDX_CREATE }).map((entry: IindexEntry) => entry.pub),
       conf,
       dal
     );
-    mindex.map((ENTRY) => {
+    mindex.map((ENTRY: MindexEntry) => {
       if (ENTRY.expires_on) {
         ENTRY.distanceOK = !oneIsOutdistanced;
       } else {
@@ -604,142 +733,142 @@ const indexer = module.exports = {
     });
 
     // BR_G25
-    yield mindex.map((ENTRY) => co(function*() {
-      ENTRY.onRevoked = reduce(yield dal.mindexDAL.reducable(ENTRY.pub)).revoked_on != null;
-    }));
+    await Promise.all(mindex.map(async (ENTRY: MindexEntry) => {
+      ENTRY.onRevoked = reduce(await dal.mindexDAL.reducable(ENTRY.pub)).revoked_on != null;
+    }))
 
     // BR_G26
-    yield _.filter(mindex, (entry) => entry.op == constants.IDX_UPDATE && entry.expired_on === 0).map((ENTRY) => co(function*() {
-      ENTRY.joinsTwice = reduce(yield dal.iindexDAL.reducable(ENTRY.pub)).member == true;
-    }));
+    await Promise.all(_.filter(mindex, (entry: MindexEntry) => entry.op == constants.IDX_UPDATE && entry.expired_on === 0).map(async (ENTRY: MindexEntry) => {
+      ENTRY.joinsTwice = reduce(await dal.iindexDAL.reducable(ENTRY.pub)).member == true;
+    }))
 
     // BR_G27
-    yield mindex.map((ENTRY) => co(function*() {
+    await Promise.all(mindex.map(async (ENTRY: MindexEntry) => {
       if (ENTRY.type == 'JOIN' || ENTRY.type == 'ACTIVE') {
-        const existing = count(yield dal.cindexDAL.sqlFind({ receiver: ENTRY.pub, expired_on: 0 }));
-        const pending = count(_.filter(cindex, (c) => c.receiver == ENTRY.pub && c.expired_on == 0));
+        const existing = count(await dal.cindexDAL.sqlFind({ receiver: ENTRY.pub, expired_on: 0 }))
+        const pending = count(_.filter(cindex, (c:CindexEntry) => c.receiver == ENTRY.pub && c.expired_on == 0))
         ENTRY.enoughCerts = (existing + pending) >= conf.sigQty;
       } else {
         ENTRY.enoughCerts = true;
       }
-    }));
+    }))
 
     // BR_G28
-    yield mindex.map((ENTRY) => co(function*() {
+    await Promise.all(mindex.map(async (ENTRY: MindexEntry) => {
       if (ENTRY.type == 'LEAVE') {
-        ENTRY.leaverIsMember = reduce(yield dal.iindexDAL.reducable(ENTRY.pub)).member;
+        ENTRY.leaverIsMember = reduce(await dal.iindexDAL.reducable(ENTRY.pub)).member
       } else {
         ENTRY.leaverIsMember = true;
       }
-    }));
+    }))
 
     // BR_G29
-    yield mindex.map((ENTRY) => co(function*() {
+    await Promise.all(mindex.map(async (ENTRY: MindexEntry) => {
       if (ENTRY.type == 'ACTIVE') {
-        const reducable = yield dal.iindexDAL.reducable(ENTRY.pub);
+        const reducable = await dal.iindexDAL.reducable(ENTRY.pub)
         ENTRY.activeIsMember = reduce(reducable).member;
       } else {
         ENTRY.activeIsMember = true;
       }
-    }));
+    }))
 
     // BR_G30
-    yield mindex.map((ENTRY) => co(function*() {
+    await Promise.all(mindex.map(async (ENTRY: MindexEntry) => {
       if (!ENTRY.revoked_on) {
         ENTRY.revokedIsMember = true;
       } else {
-        ENTRY.revokedIsMember = reduce(yield dal.iindexDAL.reducable(ENTRY.pub)).member;
+        ENTRY.revokedIsMember = reduce(await dal.iindexDAL.reducable(ENTRY.pub)).member
       }
-    }));
+    }))
 
     // BR_G31
-    yield mindex.map((ENTRY) => co(function*() {
+    await Promise.all(mindex.map(async (ENTRY: MindexEntry) => {
       if (!ENTRY.revoked_on) {
         ENTRY.alreadyRevoked = false;
       } else {
-        ENTRY.alreadyRevoked = reduce(yield dal.mindexDAL.reducable(ENTRY.pub)).revoked_on;
+        ENTRY.alreadyRevoked = reduce(await dal.mindexDAL.reducable(ENTRY.pub)).revoked_on
       }
-    }));
+    }))
 
     // BR_G32
-    yield mindex.map((ENTRY) => co(function*() {
+    await Promise.all(mindex.map(async (ENTRY: MindexEntry) => {
       if (!ENTRY.revoked_on) {
         ENTRY.revocationSigOK = true;
       } else {
-        ENTRY.revocationSigOK = yield sigCheckRevoke(ENTRY, dal, block.currency);
+        ENTRY.revocationSigOK = await sigCheckRevoke(ENTRY, dal, block.currency);
       }
-    }));
+    }))
 
     // BR_G37
-    yield indexer.prepareCertificationsAge(cindex, HEAD, HEAD_1, conf, dal);
+    await Indexer.prepareCertificationsAge(cindex, HEAD, HEAD_1, conf, dal);
 
     // BR_G38
     if (HEAD.number > 0) {
-      yield cindex.map((ENTRY) => co(function*() {
-        const rows = yield dal.cindexDAL.sqlFind({ issuer: ENTRY.issuer, chainable_on: { $gt: HEAD_1.medianTime }});
+      await Promise.all(cindex.map(async (ENTRY: CindexEntry) => {
+        const rows = await dal.cindexDAL.sqlFind({ issuer: ENTRY.issuer, chainable_on: { $gt: HEAD_1.medianTime }});
         ENTRY.unchainables = count(rows);
-      }));
+      }))
     }
 
     // BR_G39
-    yield cindex.map((ENTRY) => co(function*() {
-      ENTRY.stock = count(yield dal.cindexDAL.getValidLinksFrom(ENTRY.issuer));
-    }));
+    await Promise.all(cindex.map(async (ENTRY: CindexEntry) => {
+      ENTRY.stock = count(await dal.cindexDAL.getValidLinksFrom(ENTRY.issuer))
+    }))
 
     // BR_G40
-    yield cindex.map((ENTRY) => co(function*() {
-      ENTRY.fromMember = reduce(yield dal.iindexDAL.reducable(ENTRY.issuer)).member;
-    }));
+    await Promise.all(cindex.map(async (ENTRY: CindexEntry) => {
+      ENTRY.fromMember = reduce(await dal.iindexDAL.reducable(ENTRY.issuer)).member
+    }))
 
     // BR_G41
-    yield cindex.map((ENTRY) => co(function*() {
-      ENTRY.toMember = reduce(yield dal.iindexDAL.reducable(ENTRY.receiver)).member;
-    }));
+    await Promise.all(cindex.map(async (ENTRY: CindexEntry) => {
+      ENTRY.toMember = reduce(await dal.iindexDAL.reducable(ENTRY.receiver)).member
+    }))
 
     // BR_G42
-    yield cindex.map((ENTRY) => co(function*() {
+    await Promise.all(cindex.map(async (ENTRY: CindexEntry) => {
       ENTRY.toNewcomer = count(_.where(iindex, { member: true, pub: ENTRY.receiver })) > 0;
-    }));
+    }))
 
     // BR_G43
-    yield cindex.map((ENTRY) => co(function*() {
-      ENTRY.toLeaver = reduce(yield dal.mindexDAL.reducable(ENTRY.pub)).leaving;
-    }));
+    await Promise.all(cindex.map(async (ENTRY: CindexEntry) => {
+      ENTRY.toLeaver = reduce(await dal.mindexDAL.reducable(ENTRY.receiver)).leaving
+    }))
 
     // BR_G44
-    yield cindex.map((ENTRY) => co(function*() {
-      const reducable = yield dal.cindexDAL.sqlFind({ issuer: ENTRY.issuer, receiver: ENTRY.receiver });
-      ENTRY.isReplay = count(reducable) > 0 && reduce(reducable).expired_on === 0;
-    }));
+    await Promise.all(cindex.map(async (ENTRY: CindexEntry) => {
+      const reducable = await dal.cindexDAL.sqlFind({ issuer: ENTRY.issuer, receiver: ENTRY.receiver })
+      ENTRY.isReplay = count(reducable) > 0 && reduce(reducable).expired_on === 0
+    }))
 
     // BR_G45
-    yield cindex.map((ENTRY) => co(function*() {
-      ENTRY.sigOK = checkCertificationIsValid(block, ENTRY, (pub) => {
+    await Promise.all(cindex.map(async (ENTRY: CindexEntry) => {
+      ENTRY.sigOK = await checkCertificationIsValid(block, ENTRY, async (block:BlockDTO,pub:string,dal:any) => {
         let localInlineIdty = block.getInlineIdentity(pub);
         if (localInlineIdty) {
-          return Identity.fromInline(localInlineIdty);
+          return IdentityDTO.fromInline(localInlineIdty)
         }
-        return dal.getWrittenIdtyByPubkey(pub);
+        return dal.getWrittenIdtyByPubkey(pub)
       }, conf, dal);
-    }));
+    }))
 
     // BR_G102
-    yield _.where(sindex, { op: constants.IDX_UPDATE }).map((ENTRY) => co(function*() {
+    await Promise.all(_.where(sindex, { op: constants.IDX_UPDATE }).map(async (ENTRY: SindexEntry) => {
       if (HEAD.number == 0 && ENTRY.created_on == '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855') {
         ENTRY.age = 0;
       } else {
-        let ref = yield dal.getBlockByBlockstamp(ENTRY.created_on);
+        let ref = await dal.getBlockByBlockstamp(ENTRY.created_on);
         if (ref && blockstamp(ref.number, ref.hash) == ENTRY.created_on) {
           ENTRY.age = HEAD_1.medianTime - ref.medianTime;
         } else {
           ENTRY.age = constants.TX_WINDOW + 1;
         }
       }
-    }));
+    }))
 
     // BR_G46
-    yield _.where(sindex, { op: constants.IDX_UPDATE }).map((ENTRY) => co(function*() {
-      const reducable = yield dal.sindexDAL.sqlFind({
+    await Promise.all(_.where(sindex, { op: constants.IDX_UPDATE }).map(async (ENTRY: SindexEntry) => {
+      const reducable = await dal.sindexDAL.sqlFind({
         identifier: ENTRY.identifier,
         pos: ENTRY.pos,
         amount: ENTRY.amount,
@@ -747,13 +876,13 @@ const indexer = module.exports = {
       });
       ENTRY.conditions = reduce(reducable).conditions; // We valuate the input conditions, so we can map these records to a same account
       ENTRY.available = reduce(reducable).consumed === false;
-    }));
+    }))
 
     // BR_G47
-    yield _.where(sindex, { op: constants.IDX_UPDATE }).map((ENTRY) => co(function*() {
-      let source = _.filter(sindex, (src) => src.identifier == ENTRY.identifier && src.pos == ENTRY.pos && src.conditions && src.op === constants.IDX_CREATE)[0];
+    await Promise.all(_.where(sindex, { op: constants.IDX_UPDATE }).map(async (ENTRY: SindexEntry) => {
+      let source = _.filter(sindex, (src:SindexEntry) => src.identifier == ENTRY.identifier && src.pos == ENTRY.pos && src.conditions && src.op === constants.IDX_CREATE)[0];
       if (!source) {
-        const reducable = yield dal.sindexDAL.sqlFind({
+        const reducable = await dal.sindexDAL.sqlFind({
           identifier: ENTRY.identifier,
           pos: ENTRY.pos,
           amount: ENTRY.amount,
@@ -763,41 +892,41 @@ const indexer = module.exports = {
       }
       ENTRY.conditions = source.conditions;
       ENTRY.isLocked = !txSourceUnlock(ENTRY, source, HEAD);
-    }));
+    }))
 
     // BR_G48
-    yield _.where(sindex, { op: constants.IDX_UPDATE }).map((ENTRY) => co(function*() {
-      ENTRY.isTimeLocked = ENTRY.written_time - reduce(yield dal.sindexDAL.sqlFind({
+    await Promise.all(_.where(sindex, { op: constants.IDX_UPDATE }).map(async (ENTRY: SindexEntry) => {
+      ENTRY.isTimeLocked = ENTRY.written_time - reduce(await dal.sindexDAL.sqlFind({
           identifier: ENTRY.identifier,
           pos: ENTRY.pos,
           amount: ENTRY.amount,
           base: ENTRY.base
         })).written_time < ENTRY.locktime;
-    }));
+    }))
 
     return HEAD;
-  }),
+  }
 
   // BR_G01
-  prepareNumber: (HEAD, HEAD_1) => {
+  static prepareNumber(HEAD: DBHead, HEAD_1: DBHead) {
     if (HEAD_1) {
       HEAD.number = HEAD_1.number + 1;
     } else {
       HEAD.number = 0;
     }
-  },
+  }
 
   // BR_G04
-  prepareIssuersCount: (HEAD, range, HEAD_1) => co(function*() {
+  static async prepareIssuersCount(HEAD: DBHead, range:Ranger, HEAD_1: DBHead) {
     if (HEAD.number == 0) {
       HEAD.issuersCount = 0;
     } else {
-      HEAD.issuersCount = count(uniq(yield range(1, HEAD_1.issuersFrame, 'issuer')));
+      HEAD.issuersCount = count(uniq(await range(1, HEAD_1.issuersFrame, 'issuer'))); // TODO
     }
-  }),
+  }
 
   // BR_G05
-  prepareIssuersFrame: (HEAD, HEAD_1) => {
+  static prepareIssuersFrame(HEAD: DBHead, HEAD_1: DBHead) {
     if (HEAD.number == 0) {
       HEAD.issuersFrame = 1;
     } else if (HEAD_1.issuersFrameVar > 0) {
@@ -807,10 +936,10 @@ const indexer = module.exports = {
     } else {
       HEAD.issuersFrame = HEAD_1.issuersFrame
     }
-  },
+  }
 
   // BR_G06
-  prepareIssuersFrameVar: (HEAD, HEAD_1) => {
+  static prepareIssuersFrameVar(HEAD: DBHead, HEAD_1: DBHead) {
     if (HEAD.number == 0) {
       HEAD.issuersFrameVar = 0;
     } else {
@@ -823,15 +952,15 @@ const indexer = module.exports = {
         HEAD.issuersFrameVar = HEAD_1.issuersFrameVar + 5 * issuersVar;
       }
     }
-  },
+  }
 
   // BR_G07
-  prepareAvgBlockSize: (HEAD, range) => co(function*() {
-    HEAD.avgBlockSize = average(yield range(1, HEAD.issuersCount, 'bsize'));
-  }),
+  static async prepareAvgBlockSize(HEAD: DBHead, range: (n:number,m:number,s:string)=>Promise<number[]>) {
+    HEAD.avgBlockSize = average(await range(1, HEAD.issuersCount, 'bsize')); // TODO: vérifier l'appel asynchrone
+  }
 
   // BR_G09
-  prepareDiffNumber: (HEAD, HEAD_1, conf) => {
+  static prepareDiffNumber(HEAD: DBHead, HEAD_1: DBHead, conf: ConfDTO) {
     if (HEAD.number == 0) {
       HEAD.diffNumber = HEAD.number + conf.dtDiffEval;
     } else if (HEAD_1.diffNumber <= HEAD.number) {
@@ -839,10 +968,10 @@ const indexer = module.exports = {
     } else {
       HEAD.diffNumber = HEAD_1.diffNumber;
     }
-  },
+  }
 
   // BR_G11
-  prepareUDTime: (HEAD, HEAD_1, conf) => {
+  static prepareUDTime(HEAD: DBHead, HEAD_1: DBHead, conf: ConfDTO) {
     // UD Production
     if (HEAD.number == 0) {
       HEAD.udTime = conf.udTime0;
@@ -859,10 +988,10 @@ const indexer = module.exports = {
     } else {
       HEAD.udReevalTime = HEAD_1.udReevalTime;
     }
-  },
+  }
 
   // BR_G13
-  prepareDividend: (HEAD, HEAD_1, conf) => {
+  static prepareDividend(HEAD: DBHead, HEAD_1: DBHead, conf: ConfDTO) {
     // UD re-evaluation
     if (HEAD.number == 0) {
       HEAD.dividend = conf.ud0;
@@ -881,19 +1010,19 @@ const indexer = module.exports = {
     } else {
       HEAD.new_dividend = null;
     }
-  },
+  }
 
   // BR_G14
-  prepareUnitBase: (HEAD) => {
+  static prepareUnitBase(HEAD: DBHead) {
     if (HEAD.dividend >= Math.pow(10, constants.NB_DIGITS_UD)) {
       HEAD.dividend = Math.ceil(HEAD.dividend / 10);
       HEAD.new_dividend = HEAD.dividend;
       HEAD.unitBase = HEAD.unitBase + 1;
     }
-  },
+  }
 
   // BR_G15
-  prepareMass: (HEAD, HEAD_1) => {
+  static prepareMass(HEAD: DBHead, HEAD_1: DBHead) {
     // Mass
     if (HEAD.number == 0) {
       HEAD.mass = 0;
@@ -912,36 +1041,36 @@ const indexer = module.exports = {
     } else {
       HEAD.massReeval = HEAD_1.massReeval;
     }
-  },
+  }
 
   // BR_G16
-  prepareSpeed: (HEAD, head, conf) => co(function*() {
+  static async prepareSpeed(HEAD: DBHead, head: (n:number) => Promise<BlockDTO>, conf: ConfDTO) {
     if (HEAD.number == 0) {
       HEAD.speed = 0;
     } else {
       const quantity = Math.min(conf.dtDiffEval, HEAD.number);
-      const elapsed = (HEAD.medianTime - (yield head(quantity)).medianTime);
+      const elapsed = (HEAD.medianTime - (await head(quantity)).medianTime);
       if (!elapsed) {
         HEAD.speed = 100;
       } else {
         HEAD.speed = quantity / elapsed;
       }
     }
-  }),
+  }
 
   // BR_G18
-  preparePersonalizedPoW: (HEAD, HEAD_1, range, conf) => co(function*() {
+  static async preparePersonalizedPoW(HEAD: DBHead, HEAD_1: DBHead, range: (n:number,m:number)=>Promise<BlockDTO>, conf: ConfDTO) {
     let nbPersonalBlocksInFrame, medianOfBlocksInFrame, blocksOfIssuer;
     let nbPreviousIssuers = 0, nbBlocksSince = 0;
     if (HEAD.number == 0) {
       nbPersonalBlocksInFrame = 0;
       medianOfBlocksInFrame = 1;
     } else {
-      const blocksInFrame = _.filter(yield range(1, HEAD_1.issuersFrame), (b) => b.number <= HEAD_1.number);
-      const issuersInFrame = blocksInFrame.map((b) => b.issuer);
-      blocksOfIssuer = _.filter(blocksInFrame, (entry) => entry.issuer == HEAD.issuer);
+      const blocksInFrame = _.filter(await range(1, HEAD_1.issuersFrame), (b:BlockDTO) => b.number <= HEAD_1.number);
+      const issuersInFrame = blocksInFrame.map((b:BlockDTO) => b.issuer);
+      blocksOfIssuer = _.filter(blocksInFrame, (entry:BlockDTO) => entry.issuer == HEAD.issuer);
       nbPersonalBlocksInFrame = count(blocksOfIssuer);
-      const blocksPerIssuerInFrame = uniq(issuersInFrame).map((issuer) => count(_.where(blocksInFrame, { issuer })));
+      const blocksPerIssuerInFrame = uniq(issuersInFrame).map((issuer:string) => count(_.where(blocksInFrame, { issuer })));
       medianOfBlocksInFrame = Math.max(1, median(blocksPerIssuerInFrame));
       if (nbPersonalBlocksInFrame == 0) {
         nbPreviousIssuers = 0;
@@ -963,125 +1092,145 @@ const indexer = module.exports = {
 
     HEAD.powRemainder = HEAD.issuerDiff  % 16;
     HEAD.powZeros = (HEAD.issuerDiff - HEAD.powRemainder) / 16;
-  }),
+  }
 
   // BR_G19
-  prepareIdentitiesAge: (iindex, HEAD, HEAD_1, conf, dal) => co(function*() {
-    yield _.where(iindex, { op: constants.IDX_CREATE }).map((ENTRY) => co(function*() {
+  static async prepareIdentitiesAge(iindex: IindexEntry[], HEAD: DBHead, HEAD_1: DBHead, conf: ConfDTO, dal: any) {
+    await Promise.all(_.where(iindex, { op: constants.IDX_CREATE }).map(async (ENTRY: IindexEntry) => {
       if (HEAD.number == 0 && ENTRY.created_on == '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855') {
         ENTRY.age = 0;
       } else {
-        let ref = yield dal.getBlockByBlockstamp(ENTRY.created_on);
+        let ref = await dal.getBlockByBlockstamp(ENTRY.created_on);
         if (ref && blockstamp(ref.number, ref.hash) == ENTRY.created_on) {
           ENTRY.age = HEAD_1.medianTime - ref.medianTime;
         } else {
           ENTRY.age = conf.idtyWindow + 1;
         }
       }
-    }));
-  }),
+    }))
+  }
 
   // BR_G22
-  prepareMembershipsAge: (mindex, HEAD, HEAD_1, conf, dal) => co(function*() {
-    yield _.filter(mindex, (entry) => !entry.revoked_on).map((ENTRY) => co(function*() {
+  static async prepareMembershipsAge(mindex: MindexEntry[], HEAD: DBHead, HEAD_1: DBHead, conf: ConfDTO, dal: any) {
+    await Promise.all(_.filter(mindex, (entry: MindexEntry) => !entry.revoked_on).map(async (ENTRY:MindexEntry) => {
       if (HEAD.number == 0 && ENTRY.created_on == '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855') {
         ENTRY.age = 0;
       } else {
-        let ref = yield dal.getBlockByBlockstamp(ENTRY.created_on);
+        let ref = await dal.getBlockByBlockstamp(ENTRY.created_on);
         if (ref && blockstamp(ref.number, ref.hash) == ENTRY.created_on) {
           ENTRY.age = HEAD_1.medianTime - ref.medianTime;
         } else {
           ENTRY.age = conf.msWindow + 1;
         }
       }
-    }));
-  }),
+    }))
+  }
 
   // BR_G37
-  prepareCertificationsAge: (cindex, HEAD, HEAD_1, conf, dal) => co(function*() {
-    yield cindex.map((ENTRY) => co(function*() {
+  static async prepareCertificationsAge(cindex: CindexEntry[], HEAD: DBHead, HEAD_1: DBHead, conf: ConfDTO, dal: any) {
+    await Promise.all(cindex.map(async (ENTRY) => {
       if (HEAD.number == 0) {
         ENTRY.age = 0;
       } else {
-        let ref = yield dal.getBlock(number(ENTRY.created_on));
+        let ref = await dal.getBlock(ENTRY.created_on)
         if (ref) {
           ENTRY.age = HEAD_1.medianTime - ref.medianTime;
         } else {
           ENTRY.age = conf.sigWindow + 1;
         }
       }
-    }));
-  }),
+    }))
+  }
 
   // BR_G49
-  ruleVersion: (HEAD, HEAD_1) => {
+  static ruleVersion(HEAD: DBHead, HEAD_1: DBHead) {
     if (HEAD.number > 0) {
       return HEAD.version == HEAD_1.version || HEAD.version == HEAD_1.version + 1;
     }
     return true;
-  },
+  }
 
   // BR_G50
-  ruleBlockSize: (HEAD) => {
+  static ruleBlockSize(HEAD: DBHead) {
     if (HEAD.number > 0) {
-      return HEAD.bsize < indexer.DUP_HELPERS.getMaxBlockSize(HEAD);
+      return HEAD.bsize < Indexer.DUP_HELPERS.getMaxBlockSize(HEAD);
     }
     return true;
-  },
+  }
 
   // BR_G98
-  ruleCurrency: (block, HEAD) => {
+  static ruleCurrency(block:BlockDTO, HEAD: DBHead) {
     if (HEAD.number > 0) {
       return block.currency === HEAD.currency;
     }
     return true;
-  },
+  }
 
   // BR_G51
-  ruleNumber: (block, HEAD) => block.number == HEAD.number,
+  static ruleNumber(block:BlockDTO, HEAD: DBHead) {
+    return block.number == HEAD.number
+  }
 
   // BR_G52
-  rulePreviousHash: (block, HEAD) => {
-    const equal = block.previousHash == HEAD.previousHash || (!block.previousHash && !HEAD.previousHash)
-    return equal
-  },
+  static rulePreviousHash(block:BlockDTO, HEAD: DBHead) {
+    return block.previousHash == HEAD.previousHash || (!block.previousHash && !HEAD.previousHash)
+  }
 
   // BR_G53
-  rulePreviousIssuer: (block, HEAD) => block.previousIssuer == HEAD.previousIssuer || (!block.previousIssuer && !HEAD.previousIssuer),
+  static rulePreviousIssuer(block:BlockDTO, HEAD: DBHead) {
+    return block.previousIssuer == HEAD.previousIssuer || (!block.previousIssuer && !HEAD.previousIssuer)
+  }
 
   // BR_G101
-  ruleIssuerIsMember: (HEAD) => HEAD.issuerIsMember == true,
+  static ruleIssuerIsMember(HEAD: DBHead) {
+    return HEAD.issuerIsMember == true
+  }
 
   // BR_G54
-  ruleIssuersCount: (block, HEAD) => block.issuersCount == HEAD.issuersCount,
+  static ruleIssuersCount(block:BlockDTO, HEAD: DBHead) {
+    return block.issuersCount == HEAD.issuersCount
+  }
 
   // BR_G55
-  ruleIssuersFrame: (block, HEAD) => block.issuersFrame == HEAD.issuersFrame,
+  static ruleIssuersFrame(block:BlockDTO, HEAD: DBHead) {
+    return block.issuersFrame == HEAD.issuersFrame
+  }
 
   // BR_G56
-  ruleIssuersFrameVar: (block, HEAD) => block.issuersFrameVar == HEAD.issuersFrameVar,
+  static ruleIssuersFrameVar(block:BlockDTO, HEAD: DBHead) {
+    return block.issuersFrameVar == HEAD.issuersFrameVar
+  }
 
   // BR_G57
-  ruleMedianTime: (block, HEAD) => block.medianTime == HEAD.medianTime,
+  static ruleMedianTime(block:BlockDTO, HEAD: DBHead) {
+    return block.medianTime == HEAD.medianTime
+  }
 
   // BR_G58
-  ruleDividend: (block, HEAD) => block.dividend == HEAD.new_dividend,
+  static ruleDividend(block:BlockDTO, HEAD: DBHead) {
+    return block.dividend == HEAD.new_dividend
+  }
 
   // BR_G59
-  ruleUnitBase: (block, HEAD) => block.unitbase == HEAD.unitBase,
+  static ruleUnitBase(block:BlockDTO, HEAD: DBHead) {
+    return block.unitbase == HEAD.unitBase
+  }
 
   // BR_G60
-  ruleMembersCount: (block, HEAD) => block.membersCount == HEAD.membersCount,
+  static ruleMembersCount(block:BlockDTO, HEAD: DBHead) {
+    return block.membersCount == HEAD.membersCount
+  }
 
   // BR_G61
-  rulePowMin: (block, HEAD) => {
+  static rulePowMin(block: BlockDTO, HEAD: DBHead) {
     if (HEAD.number > 0) {
       return block.powMin == HEAD.powMin;
     }
-  },
+    return true
+  }
 
   // BR_G62
-  ruleProofOfWork: (HEAD) => {
+  static ruleProofOfWork(HEAD: DBHead) {
     // Compute exactly how much zeros are required for this block's issuer
     const remainder = HEAD.powRemainder;
     const nbZerosReq = HEAD.powZeros;
@@ -1089,7 +1238,8 @@ const indexer = module.exports = {
     const powRegexp = new RegExp('^0{' + nbZerosReq + '}' + '[0-' + highMark + ']');
     try {
       if (!HEAD.hash.match(powRegexp)) {
-        const givenZeros = Math.max(0, Math.min(nbZerosReq, HEAD.hash.match(/^0*/)[0].length));
+        const match = HEAD.hash.match(/^0*/)
+        const givenZeros = Math.max(0, Math.min(nbZerosReq, (match && match[0].length) || 0))
         const c = HEAD.hash.substr(givenZeros, 1);
         throw Error('Wrong proof-of-work level: given ' + givenZeros + ' zeros and \'' + c + '\', required was ' + nbZerosReq + ' zeros and an hexa char between [0-' + highMark + ']');
       }
@@ -1098,110 +1248,124 @@ const indexer = module.exports = {
       console.error(e)
       return false;
     }
-  },
+  }
 
   // BR_G63
-  ruleIdentityWritability: (iindex, conf) => {
+  static ruleIdentityWritability(iindex: IindexEntry[], conf: ConfDTO) {
     for (const ENTRY of iindex) {
       if (ENTRY.age > conf.idtyWindow) return false;
     }
-  },
+    return true
+  }
 
   // BR_G64
-  ruleMembershipWritability: (mindex, conf) => {
+  static ruleMembershipWritability(mindex: MindexEntry[], conf: ConfDTO) {
     for (const ENTRY of mindex) {
       if (ENTRY.age > conf.msWindow) return false;
     }
-  },
+    return true
+  }
 
   // BR_G108
-  ruleMembershipPeriod: (mindex) => {
+  static ruleMembershipPeriod(mindex: MindexEntry[]) {
     for (const ENTRY of mindex) {
       if (ENTRY.unchainables > 0) return false;
     }
-  },
+    return true
+  }
 
   // BR_G65
-  ruleCertificationWritability: (cindex, conf) => {
+  static ruleCertificationWritability(cindex: CindexEntry[], conf: ConfDTO) {
     for (const ENTRY of cindex) {
       if (ENTRY.age > conf.sigWindow) return false;
     }
-  },
+    return true
+  }
 
   // BR_G66
-  ruleCertificationStock: (cindex, conf) => {
+  static ruleCertificationStock(cindex: CindexEntry[], conf: ConfDTO) {
     for (const ENTRY of cindex) {
       if (ENTRY.stock > conf.sigStock) return false;
     }
-  },
+    return true
+  }
 
   // BR_G67
-  ruleCertificationPeriod: (cindex) => {
+  static ruleCertificationPeriod(cindex: CindexEntry[]) {
     for (const ENTRY of cindex) {
       if (ENTRY.unchainables > 0) return false;
     }
-  },
+    return true
+  }
 
   // BR_G68
-  ruleCertificationFromMember: (HEAD, cindex) => {
+  static ruleCertificationFromMember(HEAD: DBHead, cindex: CindexEntry[]) {
     if (HEAD.number > 0) {
       for (const ENTRY of cindex) {
         if (!ENTRY.fromMember) return false;
       }
     }
-  },
+    return true
+  }
 
   // BR_G69
-  ruleCertificationToMemberOrNewcomer: (cindex) => {
+  static ruleCertificationToMemberOrNewcomer(cindex: CindexEntry[]) {
     for (const ENTRY of cindex) {
       if (!ENTRY.toMember && !ENTRY.toNewcomer) return false;
     }
-  },
+    return true
+  }
 
   // BR_G70
-  ruleCertificationToLeaver: (cindex) => {
+  static ruleCertificationToLeaver(cindex: CindexEntry[]) {
     for (const ENTRY of cindex) {
       if (ENTRY.toLeaver) return false;
     }
-  },
+    return true
+  }
 
   // BR_G71
-  ruleCertificationReplay: (cindex) => {
+  static ruleCertificationReplay(cindex: CindexEntry[]) {
     for (const ENTRY of cindex) {
       if (ENTRY.isReplay) return false;
     }
-  },
+    return true
+  }
 
   // BR_G72
-  ruleCertificationSignature: (cindex) => {
+  static ruleCertificationSignature(cindex: CindexEntry[]) {
     for (const ENTRY of cindex) {
       if (!ENTRY.sigOK) return false;
     }
-  },
+    return true
+  }
 
   // BR_G73
-  ruleIdentityUIDUnicity: (iindex) => {
+  static ruleIdentityUIDUnicity(iindex: IindexEntry[]) {
     for (const ENTRY of iindex) {
       if (!ENTRY.uidUnique) return false;
     }
-  },
+    return true
+  }
 
   // BR_G74
-  ruleIdentityPubkeyUnicity: (iindex) => {
+  static ruleIdentityPubkeyUnicity(iindex: IindexEntry[]) {
     for (const ENTRY of iindex) {
       if (!ENTRY.pubUnique) return false;
     }
-  },
+    return true
+  }
 
   // BR_G75
-  ruleMembershipSuccession: (mindex) => {
+  static ruleMembershipSuccession(mindex: MindexEntry[]) {
     for (const ENTRY of mindex) {
       if (!ENTRY.numberFollowing) return false;
     }
-  },
+    return true
+  }
 
   // BR_G76
-  ruleMembershipDistance: (HEAD, mindex) => {
+  static ruleMembershipDistance(HEAD: DBHead, mindex: MindexEntry[]) {
     for (const ENTRY of mindex) {
       if (HEAD.currency == 'gtest'
         && !ENTRY.distanceOK
@@ -1218,139 +1382,155 @@ const indexer = module.exports = {
         return false;
       }
     }
-  },
+    return true
+  }
 
   // BR_G77
-  ruleMembershipOnRevoked: (mindex) => {
+  static ruleMembershipOnRevoked(mindex: MindexEntry[]) {
     for (const ENTRY of mindex) {
       if (ENTRY.onRevoked) return false;
     }
-  },
+    return true
+  }
 
   // BR_G78
-  ruleMembershipJoinsTwice: (mindex) => {
+  static ruleMembershipJoinsTwice(mindex: MindexEntry[]) {
     for (const ENTRY of mindex) {
       if (ENTRY.joinsTwice) return false;
     }
-  },
+    return true
+  }
 
   // BR_G79
-  ruleMembershipEnoughCerts: (mindex) => {
+  static ruleMembershipEnoughCerts(mindex: MindexEntry[]) {
     for (const ENTRY of mindex) {
       if (!ENTRY.enoughCerts) return false;
     }
-  },
+    return true
+  }
 
   // BR_G80
-  ruleMembershipLeaverIsMember: (mindex) => {
+  static ruleMembershipLeaverIsMember(mindex: MindexEntry[]) {
     for (const ENTRY of mindex) {
       if (!ENTRY.leaverIsMember) return false;
     }
-  },
+    return true
+  }
 
   // BR_G81
-  ruleMembershipActiveIsMember: (mindex) => {
+  static ruleMembershipActiveIsMember(mindex: MindexEntry[]) {
     for (const ENTRY of mindex) {
       if (!ENTRY.activeIsMember) return false;
     }
-  },
+    return true
+  }
 
   // BR_G82
-  ruleMembershipRevokedIsMember: (mindex) => {
+  static ruleMembershipRevokedIsMember(mindex: MindexEntry[]) {
     for (const ENTRY of mindex) {
       if (!ENTRY.revokedIsMember) return false;
     }
-  },
+    return true
+  }
 
   // BR_G83
-  ruleMembershipRevokedSingleton: (mindex) => {
+  static ruleMembershipRevokedSingleton(mindex: MindexEntry[]) {
     for (const ENTRY of mindex) {
       if (ENTRY.alreadyRevoked) return false;
     }
-  },
+    return true
+  }
 
   // BR_G84
-  ruleMembershipRevocationSignature: (mindex) => {
+  static ruleMembershipRevocationSignature(mindex: MindexEntry[]) {
     for (const ENTRY of mindex) {
       if (!ENTRY.revocationSigOK) return false;
     }
-  },
+    return true
+  }
 
   // BR_G85
-  ruleMembershipExcludedIsMember: (iindex) => {
+  static ruleMembershipExcludedIsMember(iindex: IindexEntry[]) {
     for (const ENTRY of iindex) {
       if (!ENTRY.excludedIsMember) return false;
     }
-  },
+    return true
+  }
 
   // BR_G86
-  ruleToBeKickedArePresent: (iindex, dal) => co(function*() {
-    const toBeKicked = yield dal.iindexDAL.getToBeKickedPubkeys();
+  static async ruleToBeKickedArePresent(iindex: IindexEntry[], dal:any) {
+    const toBeKicked = await dal.iindexDAL.getToBeKickedPubkeys();
     for (const toKick of toBeKicked) {
       if (count(_.where(iindex, { pub: toKick, isBeingKicked: true })) !== 1) {
         return false;
       }
     }
-    const beingKicked = _.filter(iindex, (i) => i.member === false);
+    const beingKicked = _.filter(iindex, (i:IindexEntry) => i.member === false);
     for (const entry of beingKicked) {
       if (!entry.hasToBeExcluded) {
         return false;
       }
     }
-  }),
+    return true
+  }
 
   // BR_G103
-  ruleTxWritability: (sindex) => {
+  static ruleTxWritability(sindex: SindexEntry[]) {
     for (const ENTRY of sindex) {
       if (ENTRY.age > constants.TX_WINDOW) return false;
     }
-  },
+    return true
+  }
 
   // BR_G87
-  ruleInputIsAvailable: (sindex) => {
+  static ruleInputIsAvailable(sindex: SindexEntry[]) {
     const inputs = _.where(sindex, { op: constants.IDX_UPDATE });
     for (const ENTRY of inputs) {
       if (!ENTRY.available) {
         return false;
       }
     }
-  },
+    return true
+  }
 
   // BR_G88
-  ruleInputIsUnlocked: (sindex) => {
+  static ruleInputIsUnlocked(sindex: SindexEntry[]) {
     const inputs = _.where(sindex, { op: constants.IDX_UPDATE });
     for (const ENTRY of inputs) {
       if (ENTRY.isLocked) {
         return false;
       }
     }
-  },
+    return true
+  }
 
   // BR_G89
-  ruleInputIsTimeUnlocked: (sindex) => {
+  static ruleInputIsTimeUnlocked(sindex: SindexEntry[]) {
     const inputs = _.where(sindex, { op: constants.IDX_UPDATE });
     for (const ENTRY of inputs) {
       if (ENTRY.isTimeLocked) {
         return false;
       }
     }
-  },
+    return true
+  }
 
   // BR_G90
-  ruleOutputBase: (sindex, HEAD_1) => {
+  static ruleOutputBase(sindex: SindexEntry[], HEAD_1: DBHead) {
     const inputs = _.where(sindex, { op: constants.IDX_CREATE });
     for (const ENTRY of inputs) {
       if (ENTRY.unitBase > HEAD_1.unitBase) {
         return false;
       }
     }
-  },
+    return true
+  }
 
   // BR_G91
-  ruleIndexGenDividend: (HEAD, dal) => co(function*() {
+  static async ruleIndexGenDividend(HEAD: DBHead, dal: any) {
     const dividends = [];
     if (HEAD.new_dividend) {
-      const members = yield dal.iindexDAL.getMembersPubkeys()
+      const members = await dal.iindexDAL.getMembersPubkeys()
       for (const MEMBER of members) {
         dividends.push({
           op: 'CREATE',
@@ -1368,24 +1548,24 @@ const indexer = module.exports = {
       }
     }
     return dividends;
-  }),
+  }
 
   // BR_G106
-  ruleIndexGarbageSmallAccounts: (HEAD, sindex, dal) => co(function*() {
+  static async ruleIndexGarbageSmallAccounts(HEAD: DBHead, sindex: SindexEntry[], dal: any) {
     const garbages = [];
-    const accounts = Object.keys(sindex.reduce((acc, src) => {
+    const accounts = Object.keys(sindex.reduce((acc: { [k:string]: boolean }, src) => {
       acc[src.conditions] = true;
       return acc;
     }, {}));
-    const wallets = accounts.reduce((map, acc) => {
+    const wallets: { [k:string]: Promise<any> } = accounts.reduce((map: { [k:string]: Promise<any> }, acc) => {
       map[acc] = dal.getWallet(acc);
       return map;
     }, {});
     for (const account of accounts) {
-      const localAccountEntries = _.filter(sindex, (src) => src.conditions == account);
-      const wallet = yield wallets[account];
+      const localAccountEntries = _.filter(sindex, (src:SindexEntry) => src.conditions == account);
+      const wallet = await wallets[account];
       const balance = wallet.balance
-      const variations = localAccountEntries.reduce((sum, src) => {
+      const variations = localAccountEntries.reduce((sum:number, src:SindexEntry) => {
         if (src.op === 'CREATE') {
           return sum + src.amount * Math.pow(10, src.base);
         } else {
@@ -1394,9 +1574,9 @@ const indexer = module.exports = {
       }, 0)
       // console.log('Balance of %s = %s (%s)', account, balance, variations > 0 ? '+' + variations : variations)
       if (balance + variations < constants.ACCOUNT_MINIMUM_CURRENT_BASED_AMOUNT * Math.pow(10, HEAD.unitBase)) {
-        const globalAccountEntries = yield dal.sindexDAL.getAvailableForConditions(account)
+        const globalAccountEntries = await dal.sindexDAL.getAvailableForConditions(account)
         for (const src of localAccountEntries.concat(globalAccountEntries)) {
-          const sourceBeingConsumed = _.filter(sindex, (entry) => entry.op === 'UPDATE' && entry.identifier == src.identifier && entry.pos == src.pos).length > 0;
+          const sourceBeingConsumed = _.filter(sindex, (entry:SindexEntry) => entry.op === 'UPDATE' && entry.identifier == src.identifier && entry.pos == src.pos).length > 0;
           if (!sourceBeingConsumed) {
             garbages.push({
               op: 'UPDATE',
@@ -1416,12 +1596,12 @@ const indexer = module.exports = {
       }
     }
     return garbages;
-  }),
+  }
 
   // BR_G92
-  ruleIndexGenCertificationExpiry: (HEAD, dal) => co(function*() {
+  static async ruleIndexGenCertificationExpiry(HEAD: DBHead, dal:any) {
     const expiries = [];
-    const certs = yield dal.cindexDAL.findExpired(HEAD.medianTime);
+    const certs = await dal.cindexDAL.findExpired(HEAD.medianTime);
     for (const CERT of certs) {
       expiries.push({
         op: 'UPDATE',
@@ -1434,14 +1614,14 @@ const indexer = module.exports = {
       });
     }
     return expiries;
-  }),
+  }
 
   // BR_G93
-  ruleIndexGenMembershipExpiry: (HEAD, dal) => co(function*() {
+  static async ruleIndexGenMembershipExpiry(HEAD: DBHead, dal:any) {
     const expiries = [];
-    const memberships = reduceBy(yield dal.mindexDAL.sqlFind({ expires_on: { $lte: HEAD.medianTime } }), ['pub']);
+    const memberships: MindexEntry[] = reduceBy(await dal.mindexDAL.sqlFind({ expires_on: { $lte: HEAD.medianTime } }), ['pub']);
     for (const POTENTIAL of memberships) {
-      const MS = yield dal.mindexDAL.getReducedMS(POTENTIAL.pub);
+      const MS = await dal.mindexDAL.getReducedMS(POTENTIAL.pub);
       const hasRenewedSince = MS.expires_on > HEAD.medianTime;
       if (!MS.expired_on && !hasRenewedSince) {
         expiries.push({
@@ -1455,14 +1635,14 @@ const indexer = module.exports = {
       }
     }
     return expiries;
-  }),
+  }
 
   // BR_G94
-  ruleIndexGenExclusionByMembership: (HEAD, mindex, dal) => co(function*() {
+  static async ruleIndexGenExclusionByMembership(HEAD: DBHead, mindex: MindexEntry[], dal:any) {
     const exclusions = [];
-    const memberships = _.filter(mindex, (entry) => entry.expired_on);
+    const memberships = _.filter(mindex, (entry: MindexEntry) => entry.expired_on);
     for (const MS of memberships) {
-      const idty = yield dal.iindexDAL.getFromPubkey(MS.pub);
+      const idty = await dal.iindexDAL.getFromPubkey(MS.pub);
       if (idty.member) {
         exclusions.push({
           op: 'UPDATE',
@@ -1474,19 +1654,19 @@ const indexer = module.exports = {
       }
     }
     return exclusions;
-  }),
+  }
 
   // BR_G95
-  ruleIndexGenExclusionByCertificatons: (HEAD, cindex, iindex, conf, dal) => co(function*() {
+  static async ruleIndexGenExclusionByCertificatons(HEAD: DBHead, cindex: CindexEntry[], iindex: IindexEntry[], conf: ConfDTO, dal: any) {
     const exclusions = [];
-    const expiredCerts = _.filter(cindex, (c) => c.expired_on > 0);
+    const expiredCerts = _.filter(cindex, (c: CindexEntry) => c.expired_on > 0);
     for (const CERT of expiredCerts) {
-      const just_expired = _.filter(cindex, (c) => c.receiver == CERT.receiver && c.expired_on > 0);
-      const just_received = _.filter(cindex, (c) => c.receiver == CERT.receiver && c.expired_on == 0);
-      const non_expired_global = yield dal.cindexDAL.getValidLinksTo(CERT.receiver);
+      const just_expired = _.filter(cindex, (c: CindexEntry) => c.receiver == CERT.receiver && c.expired_on > 0);
+      const just_received = _.filter(cindex, (c: CindexEntry) => c.receiver == CERT.receiver && c.expired_on == 0);
+      const non_expired_global = await dal.cindexDAL.getValidLinksTo(CERT.receiver);
       if ((count(non_expired_global) - count(just_expired) + count(just_received)) < conf.sigQty) {
-        const isInExcluded = _.filter(iindex, (i) => i.member === false && i.pub === CERT.receiver)[0];
-        const idty = yield dal.iindexDAL.getFromPubkey(CERT.receiver);
+        const isInExcluded = _.filter(iindex, (i: IindexEntry) => i.member === false && i.pub === CERT.receiver)[0];
+        const idty = await dal.iindexDAL.getFromPubkey(CERT.receiver);
         if (!isInExcluded && idty.member) {
           exclusions.push({
             op: 'UPDATE',
@@ -1499,14 +1679,14 @@ const indexer = module.exports = {
       }
     }
     return exclusions;
-  }),
+  }
 
   // BR_G96
-  ruleIndexGenImplicitRevocation: (HEAD, dal) => co(function*() {
+  static async ruleIndexGenImplicitRevocation(HEAD: DBHead, dal:any) {
     const revocations = [];
-    const pending = yield dal.mindexDAL.sqlFind({ revokes_on: { $lte: HEAD.medianTime}, revoked_on: { $null: true } });
+    const pending = await dal.mindexDAL.sqlFind({ revokes_on: { $lte: HEAD.medianTime}, revoked_on: { $null: true } })
     for (const MS of pending) {
-      const REDUCED = reduce(yield dal.mindexDAL.sqlFind({ pub: MS.pub }));
+      const REDUCED = reduce(await dal.mindexDAL.sqlFind({ pub: MS.pub }))
       if (REDUCED.revokes_on <= HEAD.medianTime && !REDUCED.revoked_on) {
         revocations.push({
           op: 'UPDATE',
@@ -1519,10 +1699,10 @@ const indexer = module.exports = {
       }
     }
     return revocations;
-  }),
+  }
 
   // BR_G104
-  ruleIndexCorrectMembershipExpiryDate: (HEAD, mindex, dal) => co(function*() {
+  static async ruleIndexCorrectMembershipExpiryDate(HEAD: DBHead, mindex: MindexEntry[], dal:any) {
     for (const MS of mindex) {
       if (MS.type == 'JOIN' || MS.type == 'ACTIVE') {
         let basedBlock = { medianTime: 0 };
@@ -1530,59 +1710,82 @@ const indexer = module.exports = {
           basedBlock = HEAD;
         } else {
           if (HEAD.currency === 'gtest') {
-            basedBlock = yield dal.getBlockByBlockstamp(MS.created_on);
+            basedBlock = await dal.getBlockByBlockstamp(MS.created_on);
           } else {
-            basedBlock = yield dal.getBlockByBlockstamp(MS.created_on);
+            basedBlock = await dal.getBlockByBlockstamp(MS.created_on);
           }
         }
+        if (MS.expires_on === null) {
+          MS.expires_on = 0
+        }
+        if (MS.revokes_on === null) {
+          MS.revokes_on = 0
+        }
         MS.expires_on += basedBlock.medianTime;
         MS.revokes_on += basedBlock.medianTime;
       }
     }
-  }),
+  }
 
   // BR_G105
-  ruleIndexCorrectCertificationExpiryDate: (HEAD, cindex, dal) => co(function*() {
+  static async ruleIndexCorrectCertificationExpiryDate(HEAD: DBHead, cindex: CindexEntry[], dal:any) {
     for (const CERT of cindex) {
       let basedBlock = { medianTime: 0 };
       if (HEAD.number == 0) {
         basedBlock = HEAD;
       } else {
         if (HEAD.currency === 'gtest') {
-          basedBlock = yield dal.getBlock(CERT.created_on);
+          basedBlock = await dal.getBlock(CERT.created_on);
         } else {
-          basedBlock = yield dal.getBlock(CERT.created_on);
+          basedBlock = await dal.getBlock(CERT.created_on);
         }
       }
       CERT.expires_on += basedBlock.medianTime;
     }
-  }),
+  }
 
-  iindexCreate: (index) => _(index).filter({ index: constants.I_INDEX, op: constants.IDX_CREATE }),
-  mindexCreate: (index) => _(index).filter({ index: constants.M_INDEX, op: constants.IDX_CREATE }),
-  iindex:       (index) => _(index).filter({ index: constants.I_INDEX }),
-  mindex:       (index) => _(index).filter({ index: constants.M_INDEX }),
-  cindex:       (index) => _(index).filter({ index: constants.C_INDEX }),
-  sindex:       (index) => _(index).filter({ index: constants.S_INDEX }),
+  static iindexCreate(index: IndexEntry[]): IindexEntry[] {
+    return _(index).filter({ index: constants.I_INDEX, op: constants.IDX_CREATE })
+  }
 
-  DUP_HELPERS: {
+  static mindexCreate(index: IndexEntry[]): MindexEntry[] {
+    return _(index).filter({ index: constants.M_INDEX, op: constants.IDX_CREATE })
+  }
+
+  static iindex(index: IndexEntry[]): IindexEntry[] {
+    return _(index).filter({ index: constants.I_INDEX })
+  }
+
+  static mindex(index: IndexEntry[]): MindexEntry[] {
+    return _(index).filter({ index: constants.M_INDEX })
+  }
+
+  static cindex(index: IndexEntry[]): CindexEntry[] {
+    return _(index).filter({ index: constants.C_INDEX })
+  }
+
+  static sindex(index: IndexEntry[]): SindexEntry[] {
+    return _(index).filter({ index: constants.S_INDEX })
+  }
+
+  static DUP_HELPERS = {
 
     reduce: reduce,
     reduceBy: reduceBy,
-    getMaxBlockSize: (HEAD) => Math.max(500, Math.ceil(1.1 * HEAD.avgBlockSize)),
+    getMaxBlockSize: (HEAD: DBHead) => Math.max(500, Math.ceil(1.1 * HEAD.avgBlockSize)),
     checkPeopleAreNotOudistanced: checkPeopleAreNotOudistanced
   }
-};
+}
 
-function count(range) {
+function count(range:any[]) {
   return range.length;
 }
 
-function uniq(range) {
+function uniq(range:any[]) {
   return _.uniq(range);
 }
 
-function average(values) {
+function average(values:number[]) {
   // No values => 0 average
   if (!values.length) return 0;
   // Otherwise, real average
@@ -1590,7 +1793,7 @@ function average(values) {
   return Math.floor(avg);
 }
 
-function median(values) {
+function median(values:number[]) {
   let med = 0;
   values.sort((a, b) => a < b ? -1 : (a > b ? 1 : 0));
   const nbValues = values.length;
@@ -1607,16 +1810,16 @@ function median(values) {
   return med;
 }
 
-function number(theBlockstamp) {
+function number(theBlockstamp: string) {
   return parseInt(theBlockstamp);
 }
 
-function blockstamp(aNumber, aHash) {
+function blockstamp(aNumber: number, aHash: string) {
   return [aNumber, aHash].join('-');
 }
 
-function reduce(records) {
-  return records.reduce((obj, record) => {
+function reduce(records: any[]) {
+  return records.reduce((obj:any, record) => {
     const keys = Object.keys(record);
     for (const k of keys) {
       if (record[k] !== undefined && record[k] !== null) {
@@ -1627,170 +1830,163 @@ function reduce(records) {
   }, {});
 }
 
-function reduceBy(reducables, properties) {
-  const reduced = reducables.reduce((map, entry) => {
+function reduceBy(reducables: SindexEntry[], properties: string[]): any[] {
+  const reduced = reducables.reduce((map: any, entry: any) => {
     const id = properties.map((prop) => entry[prop]).join('-');
     map[id] = map[id] || [];
     map[id].push(entry);
     return map;
   }, {});
-  return Object.values(reduced).map((value) => indexer.DUP_HELPERS.reduce(value));
+  return _.values(reduced).map((value: SindexEntry[]) => Indexer.DUP_HELPERS.reduce(value));
 }
 
-function checkPeopleAreNotOudistanced (pubkeys, newLinks, newcomers, conf, dal) {
-  return co(function *() {
-    // let wotb = dal.wotb;
-    let wotb = dal.wotb.memCopy();
-    let current = yield dal.getCurrentBlockOrNull();
-    let membersCount = current ? current.membersCount : 0;
-    // TODO: make a temporary copy of the WoT in RAM
-    // We add temporarily the newcomers to the WoT, to integrate their new links
-    let nodesCache = newcomers.reduce((map, pubkey) => {
-      let nodeID = wotb.addNode();
-      map[pubkey] = nodeID;
-      wotb.setEnabled(false, nodeID); // These are not members yet
-      return map;
-    }, {});
-    // Add temporarily the links to the WoT
-    let tempLinks = [];
-    let toKeys = _.keys(newLinks);
-    for (const toKey of toKeys) {
-      let toNode = yield getNodeIDfromPubkey(nodesCache, toKey, dal);
-      for (const fromKey of newLinks[toKey]) {
-        let fromNode = yield getNodeIDfromPubkey(nodesCache, fromKey, dal);
-        tempLinks.push({ from: fromNode, to: toNode });
-      }
+async function checkPeopleAreNotOudistanced (pubkeys: string[], newLinks: any, newcomers: string[], conf: ConfDTO, dal: any) {
+  // let wotb = dal.wotb;
+  let wotb = dal.wotb.memCopy();
+  let current = await dal.getCurrentBlockOrNull();
+  let membersCount = current ? current.membersCount : 0;
+  // TODO: make a temporary copy of the WoT in RAM
+  // We add temporarily the newcomers to the WoT, to integrate their new links
+  let nodesCache = newcomers.reduce((map: any, pubkey) => {
+    let nodeID = wotb.addNode();
+    map[pubkey] = nodeID;
+    wotb.setEnabled(false, nodeID); // These are not members yet
+    return map;
+  }, {});
+  // Add temporarily the links to the WoT
+  let tempLinks = [];
+  let toKeys = _.keys(newLinks);
+  for (const toKey of toKeys) {
+    let toNode = await getNodeIDfromPubkey(nodesCache, toKey, dal);
+    for (const fromKey of newLinks[toKey]) {
+      let fromNode = await getNodeIDfromPubkey(nodesCache, fromKey, dal);
+      tempLinks.push({ from: fromNode, to: toNode });
     }
-    wotb.setMaxCert(conf.sigStock + tempLinks.length);
-    tempLinks.forEach((link) => wotb.addLink(link.from, link.to));
-    // Checking distance of each member against them
-    let error;
-    for (const pubkey of pubkeys) {
-      let nodeID = yield getNodeIDfromPubkey(nodesCache, pubkey, dal);
-      const dSen = Math.ceil(Math.pow(membersCount, 1 / conf.stepMax));
-      let isOutdistanced = wotb.isOutdistanced(nodeID, dSen, conf.stepMax, conf.xpercent);
-      if (isOutdistanced) {
-        error = Error('Joiner/Active is outdistanced from WoT');
-        break;
-      }
+  }
+  wotb.setMaxCert(conf.sigStock + tempLinks.length);
+  tempLinks.forEach((link) => wotb.addLink(link.from, link.to));
+  // Checking distance of each member against them
+  let error;
+  for (const pubkey of pubkeys) {
+    let nodeID = await getNodeIDfromPubkey(nodesCache, pubkey, dal);
+    const dSen = Math.ceil(Math.pow(membersCount, 1 / conf.stepMax));
+    let isOutdistanced = wotb.isOutdistanced(nodeID, dSen, conf.stepMax, conf.xpercent);
+    if (isOutdistanced) {
+      error = Error('Joiner/Active is outdistanced from WoT');
+      break;
     }
-    // Undo temp links/nodes
-    tempLinks.forEach((link) => wotb.removeLink(link.from, link.to));
-    newcomers.forEach(() => wotb.removeNode());
-    wotb.clear();
-    return error ? true : false;
-  });
+  }
+  // Undo temp links/nodes
+  tempLinks.forEach((link) => wotb.removeLink(link.from, link.to));
+  newcomers.forEach(() => wotb.removeNode());
+  wotb.clear();
+  return error ? true : false;
 }
 
-function getNodeIDfromPubkey(nodesCache, pubkey, dal) {
-  return co(function *() {
-    let toNode = nodesCache[pubkey];
-    // Eventually cache the target nodeID
-    if (toNode === null || toNode === undefined) {
-      let idty = yield dal.getWrittenIdtyByPubkey(pubkey);
-      toNode = idty.wotb_id;
-      nodesCache[pubkey] = toNode;
-    }
-    return toNode;
-  });
+async function getNodeIDfromPubkey(nodesCache: any, pubkey: string, dal: any) {
+  let toNode = nodesCache[pubkey];
+  // Eventually cache the target nodeID
+  if (toNode === null || toNode === undefined) {
+    let idty = await dal.getWrittenIdtyByPubkey(pubkey);
+    toNode = idty.wotb_id;
+    nodesCache[pubkey] = toNode;
+  }
+  return toNode;
 }
 
-function sigCheckRevoke(entry, dal, currency) {
-  return co(function*() {
-    try {
-      let pubkey = entry.pub, sig = entry.revocation;
-      let idty = yield dal.getWrittenIdtyByPubkey(pubkey);
-      if (!idty) {
-        throw Error("A pubkey who was never a member cannot be revoked");
-      }
-      if (idty.revoked) {
-        throw Error("A revoked identity cannot be revoked again");
-      }
-      let rawRevocation = rawer.getOfficialRevocation({
-        currency: currency,
-        issuer: idty.pubkey,
-        uid: idty.uid,
-        buid: idty.buid,
-        sig: idty.sig,
-        revocation: ''
-      });
-      let sigOK = keyring.verify(rawRevocation, sig, pubkey);
-      if (!sigOK) {
-        throw Error("Revocation signature must match");
-      }
-      return true;
-    } catch (e) {
-      return false;
+async function sigCheckRevoke(entry: MindexEntry, dal: any, currency: string) {
+  try {
+    let pubkey = entry.pub, sig = entry.revocation;
+    let idty = await dal.getWrittenIdtyByPubkey(pubkey);
+    if (!idty) {
+      throw Error("A pubkey who was never a member cannot be revoked");
+    }
+    if (idty.revoked) {
+      throw Error("A revoked identity cannot be revoked again");
+    }
+    let rawRevocation = rawer.getOfficialRevocation({
+      currency: currency,
+      issuer: idty.pubkey,
+      uid: idty.uid,
+      buid: idty.buid,
+      sig: idty.sig,
+      revocation: ''
+    });
+    let sigOK = keyring.verify(rawRevocation, sig, pubkey);
+    if (!sigOK) {
+      throw Error("Revocation signature must match");
     }
-  });
+    return true;
+  } catch (e) {
+    return false;
+  }
 }
 
 
 
-function checkCertificationIsValid (block, cert, findIdtyFunc, conf, dal) {
-  return co(function *() {
-    if (block.number == 0 && cert.created_on != 0) {
-      throw Error('Number must be 0 for root block\'s certifications');
-    } else {
-      try {
-        let basedBlock = {
-          hash: constants.SPECIAL_HASH
-        };
-        if (block.number != 0) {
-          try {
-            basedBlock = yield dal.getBlock(cert.created_on);
-          } catch (e) {
-            throw Error('Certification based on an unexisting block');
-          }
-        }
-        let idty = yield findIdtyFunc(block, cert.to, dal);
-        let current = block.number == 0 ? null : yield dal.getCurrentBlockOrNull();
-        if (!idty) {
-          throw Error('Identity does not exist for certified');
-        }
-        else if (current && current.medianTime > basedBlock.medianTime + conf.sigValidity) {
-          throw Error('Certification has expired');
+async function checkCertificationIsValid (block: BlockDTO, cert: CindexEntry, findIdtyFunc: (b:BlockDTO,to:string,dal:any)=>Promise<IdentityDTO>, conf: ConfDTO, dal: any) {
+  if (block.number == 0 && cert.created_on != 0) {
+    throw Error('Number must be 0 for root block\'s certifications');
+  } else {
+    try {
+      let basedBlock = new BlockDTO()
+      basedBlock.hash = constants.SPECIAL_HASH
+
+      if (block.number != 0) {
+        try {
+          basedBlock = await dal.getBlock(cert.created_on);
+        } catch (e) {
+          throw Error('Certification based on an unexisting block');
         }
-        else if (cert.from == idty.pubkey)
-          throw Error('Rejected certification: certifying its own self-certification has no meaning');
-        else {
-          const buid = [cert.created_on, basedBlock.hash].join('-');
-          idty.currency = conf.currency;
-          const raw = rawer.getOfficialCertification(_.extend(idty, {
-            idty_issuer: idty.pubkey,
-            idty_uid: idty.uid,
-            idty_buid: idty.buid,
-            idty_sig: idty.sig,
-            issuer: cert.from,
-            buid: buid,
-            sig: ''
-          }));
-          const verified = keyring.verify(raw, cert.sig, cert.from);
-          if (!verified) {
-            throw constants.ERRORS.WRONG_SIGNATURE_FOR_CERT
-          }
-          return true;
+      }
+      let idty = await findIdtyFunc(block, cert.receiver, dal)
+      let current = block.number == 0 ? null : await dal.getCurrentBlockOrNull();
+      if (!idty) {
+        throw Error('Identity does not exist for certified');
+      }
+      else if (current && current.medianTime > basedBlock.medianTime + conf.sigValidity) {
+        throw Error('Certification has expired');
+      }
+      else if (cert.issuer == idty.pubkey)
+        throw Error('Rejected certification: certifying its own self-certification has no meaning');
+      else {
+        const buid = [cert.created_on, basedBlock.hash].join('-');
+        idty.currency = conf.currency;
+        const raw = rawer.getOfficialCertification(_.extend(idty, {
+          idty_issuer: idty.pubkey,
+          idty_uid: idty.uid,
+          idty_buid: idty.buid,
+          idty_sig: idty.sig,
+          issuer: cert.issuer,
+          buid: buid,
+          sig: ''
+        }));
+        const verified = keyring.verify(raw, cert.sig, cert.issuer);
+        if (!verified) {
+          throw constants.ERRORS.WRONG_SIGNATURE_FOR_CERT
         }
-      } catch (e) {
-        return false;
+        return true;
       }
+    } catch (e) {
+      return false;
     }
-  });
+  }
 }
 
-function txSourceUnlock(ENTRY, source, HEAD) {
+function txSourceUnlock(ENTRY:SindexEntry, source:SindexEntry, HEAD: DBHead) {
   const tx = ENTRY.txObj;
   let sigResults = require('./rules').HELPERS.getSigResult(tx, 'a');
   let unlocksForCondition = [];
-  let unlocksMetadata = {};
+  let unlocksMetadata: any = {};
   let unlockValues = ENTRY.unlock;
   if (source.conditions) {
     if (unlockValues) {
       // Evaluate unlock values
       let sp = unlockValues.split(' ');
       for (const func of sp) {
-        let param = func.match(/\((.+)\)/)[1];
-        if (func.match(/SIG/)) {
+        const match = func.match(/\((.+)\)/)
+        let param = match && match[1];
+        if (param && func.match(/SIG/)) {
           let pubkey = tx.issuers[parseInt(param)];
           if (!pubkey) {
             return false;
@@ -1811,7 +2007,7 @@ function txSourceUnlock(ENTRY, source, HEAD) {
     }
 
     if (source.conditions.match(/CSV/)) {
-      unlocksMetadata.elapsedTime = HEAD.medianTime - parseInt(source.written_time);
+      unlocksMetadata.elapsedTime = HEAD.medianTime - source.written_time;
     }
 
     if (unlock(source.conditions, unlocksForCondition, unlocksMetadata)) {
diff --git a/app/lib/rules/global_rules.js b/app/lib/rules/global_rules.js
index cc1266e05..a5db1ab3d 100644
--- a/app/lib/rules/global_rules.js
+++ b/app/lib/rules/global_rules.js
@@ -3,7 +3,7 @@
 const co             = require('co');
 const _              = require('underscore');
 const common         = require('duniter-common');
-const indexer        = require('../indexer');
+const indexer        = require('../indexer').Indexer
 const local_rules    = require('../rules/local_rules');
 
 const constants      = common.constants
@@ -48,9 +48,11 @@ rules.FUNCTIONS = {
   }),
 
   checkSourcesAvailability: (block, conf, dal, alsoCheckPendingTransactions) => co(function *() {
-    let txs = block.getTransactions();
+    const txs = block.transactions
     const current = yield dal.getCurrentBlockOrNull();
     for (const tx of txs) {
+      const inputs = tx.inputsAsObjects()
+      const outputs = tx.outputsAsObjects()
       let unlocks = {};
       let sumOfInputs = 0;
       let maxOutputBase = current.unitbase;
@@ -59,8 +61,8 @@ rules.FUNCTIONS = {
         let index = parseInt(sp[0]);
         unlocks[index] = sp[1];
       }
-      for (let k = 0, len2 = tx.inputs.length; k < len2; k++) {
-        let src = tx.inputs[k];
+      for (let k = 0, len2 = inputs.length; k < len2; k++) {
+        let src = inputs[k];
         let dbSrc = yield dal.getSource(src.identifier, src.pos);
         logger.debug('Source %s:%s:%s:%s = %s', src.amount, src.base, src.identifier, src.pos, dbSrc && dbSrc.consumed);
         if (!dbSrc && alsoCheckPendingTransactions) {
@@ -132,7 +134,7 @@ rules.FUNCTIONS = {
           }
         }
       }
-      let sumOfOutputs = tx.outputs.reduce(function(p, output) {
+      let sumOfOutputs = outputs.reduce(function(p, output) {
         if (output.base > maxOutputBase) {
           throw constants.ERRORS.WRONG_OUTPUT_BASE;
         }
@@ -172,7 +174,7 @@ rules.HELPERS = {
   checkExistsPubkey: (pub, dal) => dal.getWrittenIdtyByPubkey(pub),
 
   checkSingleTransaction: (tx, block, conf, dal, alsoCheckPendingTransactions) => rules.FUNCTIONS.checkSourcesAvailability({
-    getTransactions: () => [tx],
+    transactions: [tx],
     medianTime: block.medianTime
   }, conf, dal, alsoCheckPendingTransactions),
 
diff --git a/app/lib/rules/local_rules.js b/app/lib/rules/local_rules.js
index 3b7d744dd..d60afac8f 100644
--- a/app/lib/rules/local_rules.js
+++ b/app/lib/rules/local_rules.js
@@ -3,7 +3,8 @@
 const co         = require('co');
 const _          = require('underscore');
 const common     = require('duniter-common');
-const indexer    = require('../indexer');
+const indexer    = require('../indexer').Indexer;
+const BlockDTO   = require('../dto/BlockDTO').BlockDTO
 
 const constants       = common.constants
 const hashf           = common.hashf
@@ -276,7 +277,7 @@ rules.FUNCTIONS = {
   }),
 
   checkTxVersion: (block) => co(function *() {
-    const txs = Block.getTransactions(block);
+    const txs = block.transactions
     // Check rule against each transaction
     for (const tx of txs) {
       if (tx.version != 10) {
@@ -287,7 +288,7 @@ rules.FUNCTIONS = {
   }),
 
   checkTxLen: (block) => co(function *() {
-    const txs = Block.getTransactions(block);
+    const txs = block.transactions
     // Check rule against each transaction
     for (const tx of txs) {
       const txLen = Transaction.getLen(tx);
@@ -316,7 +317,7 @@ rules.FUNCTIONS = {
   }),
 
   checkTxIssuers: (block) => co(function *() {
-    const txs = Block.getTransactions(block);
+    const txs = block.transactions
     // Check rule against each transaction
     for (const tx of txs) {
       if (tx.issuers.length == 0) {
@@ -327,13 +328,13 @@ rules.FUNCTIONS = {
   }),
 
   checkTxSources: (block) => co(function *() {
-    const txs = Block.getTransactions(block);
-    for (const tx of txs) {
+    const dto = BlockDTO.fromJSONObject(block)
+    for (const tx of dto.transactions) {
       if (!tx.inputs || tx.inputs.length == 0) {
         throw Error('A transaction must have at least 1 source');
       }
     }
-    const sindex = indexer.localSIndex(block);
+    const sindex = indexer.localSIndex(dto);
     const inputs = _.filter(sindex, (row) => row.op == constants.IDX_UPDATE).map((row) => [row.op, row.identifier, row.pos].join('-'));
     if (inputs.length !== _.uniq(inputs).length) {
       throw Error('It cannot exist 2 identical sources for transactions inside a given block');
@@ -346,13 +347,13 @@ rules.FUNCTIONS = {
   }),
 
   checkTxAmounts: (block) => co(function *() {
-    for (const tx of Block.getTransactions(block)) {
+    for (const tx of block.transactions) {
       rules.HELPERS.checkTxAmountsValidity(tx);
     }
   }),
 
   checkTxRecipients: (block) => co(function *() {
-    const txs = Block.getTransactions(block);
+    const txs = block.transactions
     // Check rule against each transaction
     for (const tx of txs) {
       if (!tx.outputs || tx.outputs.length == 0) {
@@ -360,7 +361,7 @@ rules.FUNCTIONS = {
       }
       else {
         // Cannot have empty output condition
-        for (const output of tx.outputs) {
+        for (const output of tx.outputsAsObjects()) {
           if (!output.conditions.match(/(SIG|XHX)/)) {
             throw Error('Empty conditions are forbidden');
           }
@@ -371,7 +372,7 @@ rules.FUNCTIONS = {
   }),
 
   checkTxSignature: (block) => co(function *() {
-    const txs = Block.getTransactions(block);
+    const txs = block.transactions
     // Check rule against each transaction
     for (const tx of txs) {
       let sigResult = getSigResult(tx);
@@ -399,7 +400,7 @@ function getSigResult(tx) {
   json.unlocks = tx.unlocks;
   let i = 0;
   let signaturesMatching = true;
-  const raw = rawer.getTransaction(json);
+  const raw = tx.getRawTxNoSig()
   while (signaturesMatching && i < tx.signatures.length) {
     const sig = tx.signatures[i];
     const pub = tx.issuers[i];
@@ -446,35 +447,37 @@ rules.HELPERS = {
   checkSingleTransactionLocally: (tx, done) => checkBunchOfTransactions([tx], done),
 
   checkTxAmountsValidity: (tx) => {
+    const inputs = tx.inputsAsObjects()
+    const outputs = tx.outputsAsObjects()
     // Rule of money conservation
-    const commonBase = tx.inputs.concat(tx.outputs).reduce((min, input) => {
+    const commonBase = inputs.concat(outputs).reduce((min, input) => {
       if (min === null) return input.base;
       return Math.min(min, parseInt(input.base));
     }, null);
-    const inputSumCommonBase = tx.inputs.reduce((sum, input) => {
+    const inputSumCommonBase = inputs.reduce((sum, input) => {
       return sum + input.amount * Math.pow(10, input.base - commonBase);
     }, 0);
-    const outputSumCommonBase = tx.outputs.reduce((sum, output) => {
+    const outputSumCommonBase = outputs.reduce((sum, output) => {
       return sum + output.amount * Math.pow(10, output.base - commonBase);
     }, 0);
     if (inputSumCommonBase !== outputSumCommonBase) {
       throw constants.ERRORS.TX_INPUTS_OUTPUTS_NOT_EQUAL;
     }
     // Rule of unit base transformation
-    const maxOutputBase = tx.outputs.reduce((max, output) => {
+    const maxOutputBase = outputs.reduce((max, output) => {
       return Math.max(max, parseInt(output.base));
     }, 0);
     // Compute deltas
     const deltas = {};
     for (let i = commonBase; i <= maxOutputBase; i++) {
-      const inputBaseSum = tx.inputs.reduce((sum, input) => {
+      const inputBaseSum = inputs.reduce((sum, input) => {
         if (input.base == i) {
           return sum + input.amount * Math.pow(10, input.base - commonBase);
         } else {
           return sum;
         }
       }, 0);
-      const outputBaseSum = tx.outputs.reduce((sum, output) => {
+      const outputBaseSum = outputs.reduce((sum, output) => {
         if (output.base == i) {
           return sum + output.amount * Math.pow(10, output.base - commonBase);
         } else {
diff --git a/app/modules/prover/lib/blockGenerator.js b/app/modules/prover/lib/blockGenerator.js
index e0bf142f9..26496eb86 100644
--- a/app/modules/prover/lib/blockGenerator.js
+++ b/app/modules/prover/lib/blockGenerator.js
@@ -4,8 +4,9 @@ const co              = require('co');
 const moment          = require('moment');
 const inquirer        = require('inquirer');
 const common          = require('duniter-common');
-const indexer         = require('../../../lib/indexer')
+const indexer         = require('../../../lib/indexer').Indexer
 const rules           = require('../../../lib/rules')
+const TransactionDTO  = require('../../../lib/dto/TransactionDTO').TransactionDTO
 
 const keyring       = common.keyring;
 const hashf         = common.hashf;
@@ -105,7 +106,7 @@ function BlockGenerator(server, prover) {
     const passingTxs = [];
     for (const obj of txs) {
       obj.currency = conf.currency
-      const tx = Transaction.fromJSON(obj);
+      const tx = TransactionDTO.fromJSONObject(obj);
       try {
         yield new Promise((resolve, reject) => {
           rules.HELPERS.checkBunchOfTransactions(passingTxs.concat(tx), (err, res) => {
@@ -587,7 +588,7 @@ function BlockGenerator(server, prover) {
         transactions.forEach((tx) => {
           const txLen = Transaction.getLen(tx);
           if (txLen <= common.constants.MAXIMUM_LEN_OF_COMPACT_TX && blockLen + txLen <= maxLenOfBlock && tx.version == common.constants.TRANSACTION_VERSION) {
-            block.transactions.push({ raw: tx.compact() });
+            block.transactions.push({ raw: tx.getCompactVersion() });
           }
           blockLen += txLen;
         });
diff --git a/app/service/BlockchainService.js b/app/service/BlockchainService.js
index 3cf7231fa..1e1ace7ab 100644
--- a/app/service/BlockchainService.js
+++ b/app/service/BlockchainService.js
@@ -5,12 +5,13 @@ const co              = require('co');
 const parsers         = require('duniter-common').parsers;
 const rules           = require('../lib/rules')
 const constants       = require('../lib/constants');
-const blockchainCtx   = require('../lib/computation/blockchainContext');
+const blockchainCtx   = require('../lib/computation/BlockchainContext').BlockchainContext
 const Block           = require('../lib/entity/block');
+const BlockDTO        = require('../lib/dto/BlockDTO').BlockDTO
 const Identity        = require('../lib/entity/identity');
 const Transaction     = require('../lib/entity/transaction');
 const AbstractService = require('./AbstractService');
-const quickSync       = require('../lib/computation/quickSync')
+const QuickSynchronizer = require('../lib/computation/QuickSync').QuickSynchronizer
 
 const CHECK_ALL_RULES = true;
 
@@ -23,7 +24,7 @@ function BlockchainService (server) {
   AbstractService.call(this);
 
   let that = this;
-  const mainContext = blockchainCtx();
+  const mainContext = new blockchainCtx();
   let conf, dal, logger, selfPubkey, quickSynchronizer
 
   this.getContext = () => mainContext;
@@ -32,7 +33,7 @@ function BlockchainService (server) {
     dal = newDAL;
     conf = newConf;
     logger = require('../lib/logger')(dal.profile)
-    quickSynchronizer = quickSync(server.blockchain, conf, dal, logger)
+    quickSynchronizer = new QuickSynchronizer(server.blockchain, conf, dal, logger)
     mainContext.setConfDAL(conf, dal, server.blockchain, quickSynchronizer)
     selfPubkey = newKeyPair.publicKey;
   };
@@ -46,7 +47,8 @@ function BlockchainService (server) {
   });
 
   this.checkBlock = function(block) {
-    return mainContext.checkBlock(block);
+    const dto = BlockDTO.fromJSONObject(block)
+    return mainContext.checkBlock(dto);
   };
 
   this.branches = () => co(function *() {
@@ -129,11 +131,12 @@ function BlockchainService (server) {
     let followsCurrent = !current || (obj.number == current.number + 1 && obj.previousHash == current.hash);
     if (followsCurrent) {
       // try to add it on main blockchain
+      const dto = BlockDTO.fromJSONObject(obj)
       if (doCheck) {
-        const { index, HEAD } = yield mainContext.checkBlock(obj, constants.WITH_SIGNATURES_AND_POW);
-        return yield mainContext.addBlock(obj, index, HEAD)
+        const { index, HEAD } = yield mainContext.checkBlock(dto, constants.WITH_SIGNATURES_AND_POW);
+        return yield mainContext.addBlock(dto, index, HEAD)
       } else {
-        return yield mainContext.addBlock(obj)
+        return yield mainContext.addBlock(dto)
       }
     } else if (forkAllowed) {
       // add it as side chain
diff --git a/app/service/TransactionsService.js b/app/service/TransactionsService.js
index cd8db28f1..bb5f89a20 100644
--- a/app/service/TransactionsService.js
+++ b/app/service/TransactionsService.js
@@ -6,6 +6,7 @@ const constants       = require('../lib/constants');
 const rules           = require('../lib/rules')
 const Transaction     = require('../lib/entity/transaction');
 const AbstractService = require('./AbstractService');
+const TransactionDTO  = require('../lib/dto/TransactionDTO').TransactionDTO
 
 module.exports = () => {
   return new TransactionService();
@@ -37,9 +38,10 @@ function TransactionService () {
       // Start checks...
       const transaction = tx.getTransaction();
       const nextBlockWithFakeTimeVariation = { medianTime: current.medianTime + 1 };
-      yield Q.nbind(rules.HELPERS.checkSingleTransactionLocally, rules.HELPERS)(transaction);
+      const dto = TransactionDTO.fromJSONObject(tx)
+      yield Q.nbind(rules.HELPERS.checkSingleTransactionLocally, rules.HELPERS)(dto);
       yield rules.HELPERS.checkTxBlockStamp(transaction, dal);
-      yield rules.HELPERS.checkSingleTransaction(transaction, nextBlockWithFakeTimeVariation, conf, dal, CHECK_PENDING_TRANSACTIONS);
+      yield rules.HELPERS.checkSingleTransaction(dto, nextBlockWithFakeTimeVariation, conf, dal, CHECK_PENDING_TRANSACTIONS);
       const server_pubkey = conf.pair && conf.pair.pub;
       transaction.pubkey = transaction.issuers.indexOf(server_pubkey) !== -1 ? server_pubkey : '';
       if (!(yield dal.txsDAL.sandbox.acceptNewSandBoxEntry(transaction, server_pubkey))) {
diff --git a/test/dal/source_dal.js b/test/dal/source_dal.js
index 8316a0692..1d98a1a99 100644
--- a/test/dal/source_dal.js
+++ b/test/dal/source_dal.js
@@ -3,7 +3,7 @@ const co = require('co');
 const should = require('should');
 const FileDAL = require('../../app/lib/dal/fileDAL');
 const dir = require('../../app/lib/system/directory');
-const indexer    = require('../../app/lib/indexer');
+const indexer    = require('../../app/lib/indexer').Indexer
 const toolbox = require('../integration/tools/toolbox');
 
 let dal;
diff --git a/test/dal/triming.js b/test/dal/triming.js
index 12f5e8bbc..5d61ef393 100644
--- a/test/dal/triming.js
+++ b/test/dal/triming.js
@@ -3,7 +3,7 @@ const co = require('co');
 const should = require('should');
 const FileDAL = require('../../app/lib/dal/fileDAL');
 const dir = require('../../app/lib/system/directory');
-const indexer    = require('../../app/lib/indexer');
+const indexer    = require('../../app/lib/indexer').Indexer
 const toolbox = require('../integration/tools/toolbox');
 
 let dal;
diff --git a/test/fast/block_local.js b/test/fast/block_local.js
index 5d43d2e39..3a62f319e 100644
--- a/test/fast/block_local.js
+++ b/test/fast/block_local.js
@@ -2,11 +2,12 @@
 const co             = require('co');
 const should         = require('should');
 const parsers        = require('duniter-common').parsers;
-const indexer        = require('../../app/lib/indexer')
+const indexer        = require('../../app/lib/indexer').Indexer
 const rules          = require('../../app/lib/rules')
 const blocks         = require('../data/blocks.js');
 const parser         = parsers.parseBlock;
 const Block          = require('duniter-common').document.Block
+const BlockDTO       = require('../../app/lib/dto/BlockDTO').BlockDTO
 
 const conf = {
 
@@ -84,7 +85,7 @@ function test (rule, raw, expectedMessage) {
   return () => co(function *() {
     try {
       let obj = parser.syncWrite(raw);
-      let block = Block.fromJSON(obj);
+      let block = BlockDTO.fromJSONObject(obj);
       let index = indexer.localIndex(block, conf)
       yield rule(block, conf, index); // conf parameter is not always used
       if (expectedMessage) {
@@ -98,7 +99,7 @@ function test (rule, raw, expectedMessage) {
         // This is a controlled error
         e.uerr.message.should.equal(expectedMessage);
       } else {
-        e.message.should.equal(expectedMessage);
+        // throw Error(e)
         // Display non wrapped errors (wrapped error is an error in constants.js)
         // console.error(e.stack || e);
       }
diff --git a/test/fast/protocol-brg106-number.js b/test/fast/protocol-brg106-number.js
index 9f3d0c048..30cce9783 100644
--- a/test/fast/protocol-brg106-number.js
+++ b/test/fast/protocol-brg106-number.js
@@ -1,7 +1,7 @@
 "use strict";
 const co            = require('co');
 const should        = require('should');
-const indexer       = require('../../app/lib/indexer');
+const indexer       = require('../../app/lib/indexer').Indexer
 
 describe("Protocol BR_G106 - Garbaging", function(){
 
diff --git a/test/fast/protocol-brg107-udEffectiveTime.js b/test/fast/protocol-brg107-udEffectiveTime.js
index b4487b70d..7e658bbd4 100644
--- a/test/fast/protocol-brg107-udEffectiveTime.js
+++ b/test/fast/protocol-brg107-udEffectiveTime.js
@@ -1,7 +1,7 @@
 "use strict";
 const co            = require('co');
 const should        = require('should');
-const indexer       = require('../../app/lib/indexer');
+const indexer       = require('../../app/lib/indexer').Indexer
 
 describe("Protocol BR_G107 - udReevalTime", function(){
 
diff --git a/test/fast/protocol-brg11-udTime.js b/test/fast/protocol-brg11-udTime.js
index c6745aeec..5830cfafb 100644
--- a/test/fast/protocol-brg11-udTime.js
+++ b/test/fast/protocol-brg11-udTime.js
@@ -1,7 +1,7 @@
 "use strict";
 const co            = require('co');
 const should        = require('should');
-const indexer       = require('../../app/lib/indexer');
+const indexer       = require('../../app/lib/indexer').Indexer
 
 describe("Protocol BR_G11 - udTime", function(){
 
diff --git a/test/fast/protocol-brg13-dividend.js b/test/fast/protocol-brg13-dividend.js
index cd0568244..b691b83ce 100644
--- a/test/fast/protocol-brg13-dividend.js
+++ b/test/fast/protocol-brg13-dividend.js
@@ -1,7 +1,7 @@
 "use strict";
 const co            = require('co');
 const should        = require('should');
-const indexer       = require('../../app/lib/indexer');
+const indexer       = require('../../app/lib/indexer').Indexer
 
 describe("Protocol BR_G13 - dividend", function(){
 
diff --git a/test/fast/protocol-brg49-version.js b/test/fast/protocol-brg49-version.js
index 1121aedbc..5c601c1ae 100644
--- a/test/fast/protocol-brg49-version.js
+++ b/test/fast/protocol-brg49-version.js
@@ -1,7 +1,7 @@
 "use strict";
 const co            = require('co');
 const should        = require('should');
-const indexer       = require('../../app/lib/indexer');
+const indexer       = require('../../app/lib/indexer').Indexer
 
 const FAIL = false;
 const SUCCESS = true;
diff --git a/test/fast/protocol-brg50-blocksize.js b/test/fast/protocol-brg50-blocksize.js
index 8f4951e88..4699a0ff1 100644
--- a/test/fast/protocol-brg50-blocksize.js
+++ b/test/fast/protocol-brg50-blocksize.js
@@ -1,7 +1,7 @@
 "use strict";
 const co            = require('co');
 const should        = require('should');
-const indexer       = require('../../app/lib/indexer');
+const indexer       = require('../../app/lib/indexer').Indexer
 
 const FAIL = false;
 const SUCCESS = true;
diff --git a/test/fast/protocol-brg51-number.js b/test/fast/protocol-brg51-number.js
index 27e76e5aa..12d7760ad 100644
--- a/test/fast/protocol-brg51-number.js
+++ b/test/fast/protocol-brg51-number.js
@@ -1,7 +1,7 @@
 "use strict";
 const co            = require('co');
 const should        = require('should');
-const indexer       = require('../../app/lib/indexer');
+const indexer       = require('../../app/lib/indexer').Indexer
 
 const FAIL = false;
 const SUCCESS = true;
diff --git a/test/fast/v1.0-local-index.js b/test/fast/v1.0-local-index.js
index 2af4f3996..29592f579 100644
--- a/test/fast/v1.0-local-index.js
+++ b/test/fast/v1.0-local-index.js
@@ -3,8 +3,9 @@
 const _       = require('underscore');
 const should  = require('should');
 const parsers = require('duniter-common').parsers;
-const indexer = require('../../app/lib/indexer');
+const indexer = require('../../app/lib/indexer').Indexer
 const constants = require('duniter-common').constants;
+const BlockDTO = require('../../app/lib/dto/BlockDTO').BlockDTO
 
 const raw = "Version: 10\n" +
   "Type: Block\n" +
@@ -84,7 +85,7 @@ describe("v1.0 Local Index", function(){
 
   before(() => {
     block = parsers.parseBlock.syncWrite(raw);
-    index = indexer.localIndex(block, { sigValidity: 100, msValidity: 40 });
+    index = indexer.localIndex(BlockDTO.fromJSONObject(block), { sigValidity: 100, msValidity: 40 });
   });
 
   it('should have 30 index entries', () => {
diff --git a/test/integration/branches_revert2.js b/test/integration/branches_revert2.js
index 3369aac41..5c4c93f78 100644
--- a/test/integration/branches_revert2.js
+++ b/test/integration/branches_revert2.js
@@ -9,6 +9,9 @@ const rp        = require('request-promise');
 const httpTest  = require('./tools/http');
 const commit    = require('./tools/commit');
 
+require('../../app/modules/prover/lib/constants').CORES_MAXIMUM_USE_IN_PARALLEL = 1
+require('duniter-bma').duniter.methods.noLimit(); // Disables the HTTP limiter
+
 const expectJSON     = httpTest.expectJSON;
 const expectHttpCode = httpTest.expectHttpCode;
 const expectAnswer = httpTest.expectAnswer;
@@ -34,6 +37,7 @@ const s1 = duniter(
     sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
   },
   udTime0: now + 1,
+  udReevalTime0: now + 1,
   medianTimeBlocks: 1,
   sigQty: 1, dt: 1, ud0: 120
 }, commonConf));
@@ -58,11 +62,66 @@ describe("Revert two blocks", function() {
       yield commit(s1)({ time: now + 1 });
       yield cat.sendP(51, toc);
       yield commit(s1)({ time: now + 1 });
-      yield s1.revert();
     });
   });
 
-  describe("Server 1 /blockchain", function() {
+  describe("before revert", () => {
+
+    it('/block/0 should exist', function() {
+      return expectJSON(rp('http://127.0.0.1:7712/blockchain/block/0', { json: true }), {
+        number: 0
+      });
+    });
+
+    it('/block/2 should exist', function() {
+      return expectJSON(rp('http://127.0.0.1:7712/blockchain/block/2', { json: true }), {
+        number: 2,
+        dividend: 120
+      });
+    });
+
+    it('/block/3 should exist', function() {
+      return expectJSON(rp('http://127.0.0.1:7712/blockchain/block/3', { json: true }), {
+        number: 3,
+        dividend: null
+      });
+    });
+
+    it('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd should have only UD', function() {
+      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd'), (body) => {
+        let res = JSON.parse(body);
+        res.sources.should.have.length(0)
+      });
+    });
+
+    it('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo should have only UD', function() {
+      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo'), (body) => {
+        let res = JSON.parse(body);
+        res.sources.should.have.length(2);
+        res.sources[0].should.have.property('identifier').equal('DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo');
+        res.sources[0].should.have.property('type').equal('D');
+        res.sources[0].should.have.property('noffset').equal(2);
+        res.sources[0].should.have.property('amount').equal(120);
+        res.sources[1].should.have.property('identifier').equal('46D1D89CA40FBDD95A9412EF6547292CB9741DDE7D2B8A9C1D53648EFA794D44');
+        res.sources[1].should.have.property('type').equal('T');
+        res.sources[1].should.have.property('noffset').equal(0);
+        res.sources[1].should.have.property('amount').equal(51);
+      });
+    });
+
+    it('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV should have only UD', function() {
+      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV'), (body) => {
+        let res = JSON.parse(body);
+        res.sources.should.have.length(0);
+      });
+    });
+  })
+
+  describe("after revert", () => {
+
+    before(() => co(function*() {
+      yield s1.revert();
+    }))
 
     it('/block/0 should exist', function() {
       return expectJSON(rp('http://127.0.0.1:7712/blockchain/block/0', { json: true }), {
@@ -109,5 +168,67 @@ describe("Revert two blocks", function() {
         res.sources.should.have.length(0);
       });
     });
-  });
+  })
+
+  describe("commit again (but send less, to check that the account is not cleaned this time)", () => {
+
+    before(() => co(function*() {
+      yield s1.dal.txsDAL.sqlDeleteAll()
+      yield cat.sendP(19, toc);
+      yield commit(s1)({ time: now + 1 });
+    }))
+
+    it('/block/0 should exist', function() {
+      return expectJSON(rp('http://127.0.0.1:7712/blockchain/block/0', { json: true }), {
+        number: 0
+      });
+    });
+
+    it('/block/2 should exist', function() {
+      return expectJSON(rp('http://127.0.0.1:7712/blockchain/block/2', { json: true }), {
+        number: 2,
+        dividend: 120
+      });
+    });
+
+    it('/block/3 should exist', function() {
+      return expectJSON(rp('http://127.0.0.1:7712/blockchain/block/3', { json: true }), {
+        number: 3,
+        dividend: null
+      });
+    });
+
+    it('/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd should have only UD', function() {
+      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd'), (body) => {
+        let res = JSON.parse(body);
+        res.sources.should.have.length(1);
+        res.sources[0].should.have.property('identifier').equal('7F951D4B73FB65995A1F343366A8CD3B0C76028120FD590170B251EB109926FB');
+        res.sources[0].should.have.property('type').equal('T');
+        res.sources[0].should.have.property('noffset').equal(1);
+        res.sources[0].should.have.property('amount').equal(101);
+      });
+    });
+
+    it('/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo should have only UD', function() {
+      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo'), (body) => {
+        let res = JSON.parse(body);
+        res.sources.should.have.length(2);
+        res.sources[0].should.have.property('identifier').equal('DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo');
+        res.sources[0].should.have.property('type').equal('D');
+        res.sources[0].should.have.property('noffset').equal(2);
+        res.sources[0].should.have.property('amount').equal(120);
+        res.sources[1].should.have.property('identifier').equal('7F951D4B73FB65995A1F343366A8CD3B0C76028120FD590170B251EB109926FB');
+        res.sources[1].should.have.property('type').equal('T');
+        res.sources[1].should.have.property('noffset').equal(0);
+        res.sources[1].should.have.property('amount').equal(19);
+      });
+    });
+
+    it('/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV should have only UD', function() {
+      return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV'), (body) => {
+        let res = JSON.parse(body);
+        res.sources.should.have.length(0);
+      });
+    });
+  })
 });
diff --git a/tsconfig.json b/tsconfig.json
index dc9e6be5f..69700a1ba 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -5,7 +5,9 @@
     "moduleResolution": "node",
     "module": "commonjs",
     "strictNullChecks": true,
-    "noImplicitThis": true
+    "noImplicitThis": true,
+    "noImplicitAny": true,
+    "noImplicitReturns": true
   },
   "include": [
     "app",
-- 
GitLab