diff --git a/app/lib/common-libs/array-prune.ts b/app/lib/common-libs/array-prune.ts
index 524f9a5d91cc63185d10ed681abf93540ad6edd2..0e262d538bcf44bf7a6727066df6b58bfd073e97 100644
--- a/app/lib/common-libs/array-prune.ts
+++ b/app/lib/common-libs/array-prune.ts
@@ -11,6 +11,11 @@ export function arrayPruneAll<T>(array: T[], value: T) {
   } while (index !== -1)
 }
 
+/**
+ * Returs a copy of given array WITHOUT any record of `value`.
+ * @param original The array we want records, with `value` being excluded.
+ * @param value The value we don't want to see in our copy array.
+ */
 export function arrayPruneAllCopy<T>(original: T[], value: T) {
   const array = original.slice()
   let index
diff --git a/app/lib/common-libs/constants.ts b/app/lib/common-libs/constants.ts
index 728e506b7eb5f85bcb41f239bf87b3448cf61b56..9e44451cb5686124d7ef50e7d2be3f00c557045d 100755
--- a/app/lib/common-libs/constants.ts
+++ b/app/lib/common-libs/constants.ts
@@ -301,6 +301,7 @@ export const CommonConstants = {
   },
 
   BLOCK_MAX_TX_CHAINING_DEPTH: 5,
+  BLOCK_TX_CHAINING_ACTIVATION_MT: 1519862400,
 
   ARCHIVES_BLOCKS_CHUNK: 250,
   SYNC_BLOCKS_CHUNK: 250,
diff --git a/app/lib/dal/indexDAL/leveldb/LevelDBSindex.ts b/app/lib/dal/indexDAL/leveldb/LevelDBSindex.ts
index f4b7c469b750e13ab6712f3a6fec080af333d6ae..099a565bf2683cd8a3bdf2c7c8da45d998fa31b6 100644
--- a/app/lib/dal/indexDAL/leveldb/LevelDBSindex.ts
+++ b/app/lib/dal/indexDAL/leveldb/LevelDBSindex.ts
@@ -177,11 +177,13 @@ export class LevelDBSindex extends LevelDBTable<SindexEntry> implements SIndexDA
   }
 
   async getWrittenOn(blockstamp: string): Promise<SindexEntry[]> {
-    const ids = (await this.indexForTrimming.getOrNull(LevelDBSindex.trimWrittenOnKey(pint(blockstamp)))) || []
+    const ids = Underscore.uniq((await this.indexForTrimming.getOrNull(LevelDBSindex.trimWrittenOnKey(pint(blockstamp)))) || [])
     const found: SindexEntry[] = []
     for (const id of ids) {
       const entries = await this.findByIdentifierAndPos(id.split('-')[0], pint(id.split('-')[1]))
-      entries.forEach(e => found.push(e))
+      entries
+        .filter(e => e.written_on === blockstamp)
+        .forEach(e => found.push(e))
     }
     return found
   }
@@ -198,42 +200,65 @@ export class LevelDBSindex extends LevelDBTable<SindexEntry> implements SIndexDA
 
   async removeBlock(blockstamp: string): Promise<void> {
     const writtenOn = pint(blockstamp)
+    // We look at records written on this blockstamp: `indexForTrimming` allows to get them
     const ids = (await this.indexForTrimming.getOrNull(LevelDBSindex.trimWrittenOnKey(writtenOn))) || []
+    // `ids` contains both CREATE and UPDATE sources
     for (const id of ids) {
       // Remove sources
       const identifier = id.split('-')[0]
+      const pos = parseInt(id.split('-')[1])
       const conditions: string[] = []
-      await this.applyAllKeyValue(async kv => {
-        conditions.push(kv.value.conditions)
-        await this.del(kv.key)
-      }, {
-        gte: identifier,
-        lt: LevelDBSindex.upperIdentifier(identifier)
-      })
-      // Remove indexations
-      // 1. WrittenOn
-      await this.indexForTrimming.del(LevelDBSindex.trimWrittenOnKey(writtenOn))
-      // 2. Conditions
+      const createKey = LevelDBSindex.trimKey(identifier, pos, false)
+      const updateKey = LevelDBSindex.trimKey(identifier, pos, true)
+      const createRecord = await this.getOrNull(createKey)
+      const updateRecord = await this.getOrNull(updateKey)
+      // Undo consumption
+      if (updateRecord && updateRecord.writtenOn === writtenOn) {
+        conditions.push(updateRecord.conditions)
+        await this.del(updateKey)
+      }
+      // Undo creation?
+      if (createRecord && createRecord.writtenOn === writtenOn) {
+        conditions.push(createRecord.conditions)
+        await this.del(createKey)
+      }
+      // Update balance
+      // 1. Conditions
       const uniqConditions = Underscore.uniq(conditions)
       for (const condition of uniqConditions) {
+        // Remove this source from the balance
         await this.trimConditions(condition, id)
       }
     }
+    if (ids.length) {
+      // 2. WrittenOn
+      await this.indexForTrimming.del(LevelDBSindex.trimWrittenOnKey(writtenOn))
+      await this.indexForConsumed.del(LevelDBSindex.trimWrittenOnKey(writtenOn))
+    }
   }
 
   private async trimConditions(condition: string, id: string) {
+    // Get all the account's TX sources
     const existing = (await this.indexForConditions.getOrNull(condition)) || []
+    // Prune the source from the account
     const trimmed = arrayPruneAllCopy(existing, id)
     if (trimmed.length) {
+      // If some sources are left for this "account", persist what remains
       await this.indexForConditions.put(condition, trimmed)
     } else {
+      // Otherwise just delete the "account"
       await this.indexForConditions.del(condition)
     }
   }
 
+  /**
+   * Duplicate with trimConditions?!
+   * @param writtenOn
+   * @param id
+   */
   private async trimWrittenOn(writtenOn: number, id: string) {
     const k = LevelDBSindex.trimWrittenOnKey(writtenOn)
-    const existing = (await this.indexForTrimming.getOrNull(k)) || []
+    const existing = await this.getWrittenOnSourceIds(writtenOn)
     const trimmed = arrayPruneAllCopy(existing, id)
     if (trimmed.length) {
       await this.indexForConditions.put(k, trimmed)
@@ -253,6 +278,11 @@ export class LevelDBSindex extends LevelDBTable<SindexEntry> implements SIndexDA
     }
   }
 
+  private async getWrittenOnSourceIds(writtenOn: number) {
+    const indexForTrimmingId = LevelDBSindex.trimWrittenOnKey(writtenOn)
+    return (await this.indexForTrimming.getOrNull(indexForTrimmingId)) || []
+  }
+
   private static trimKey(identifier: string, pos: number, consumed: boolean) {
     return `${identifier}-${String(pos).padStart(10, '0')}-${consumed ? 1 : 0}`
   }
diff --git a/app/lib/indexer.ts b/app/lib/indexer.ts
index cca42a91f56e0175db425989c1b49501ba365de1..1ce20345022e992f6adcdba560c0f517b7086a0a 100644
--- a/app/lib/indexer.ts
+++ b/app/lib/indexer.ts
@@ -30,6 +30,7 @@ import {Tristamp} from "./common/Tristamp"
 import {Underscore} from "./common-libs/underscore"
 import {DataErrors} from "./common-libs/errors"
 import {MonitorExecutionTime} from "./debug/MonitorExecutionTime"
+import {NewLogger} from "./logger"
 
 const constants       = CommonConstants
 
@@ -1033,6 +1034,9 @@ export class Indexer {
           ENTRY.base,
           ENTRY.srcType === 'D'
         );
+        if (!reducable.length) {
+          NewLogger().debug('Source %s:%s NOT FOUND', ENTRY.identifier, ENTRY.pos)
+        }
         source = reduce(reducable)
       }
       return source
@@ -2157,6 +2161,9 @@ function txSourceUnlock(ENTRY:SindexEntry, source:{ conditions: string, written_
   const unlockParams:string[] = TransactionDTO.unlock2params(ENTRY.unlock || '')
   const unlocksMetadata:UnlockMetadata = {}
   const sigResult = TransactionDTO.fromJSONObject(tx).getTransactionSigResult()
+  if (!source.conditions) {
+    return false // Unlock fail
+  }
   if (source.conditions.match(/CLTV/)) {
     unlocksMetadata.currentTime = HEAD.medianTime;
   }
diff --git a/app/lib/rules/local_rules.ts b/app/lib/rules/local_rules.ts
index d6c56b1c3da7e61d07b939a047e15b3407f10ec2..35ed12a8a1ac1fad33d040cadd9dab3d198cc6ef 100644
--- a/app/lib/rules/local_rules.ts
+++ b/app/lib/rules/local_rules.ts
@@ -396,7 +396,7 @@ export const LOCAL_RULES_FUNCTIONS = {
     const sindex = Indexer.sindex(index)
     const max = getMaxTransactionDepth(sindex)
     //
-    const allowedMax = block.medianTime > 1519862400 ? CommonConstants.BLOCK_MAX_TX_CHAINING_DEPTH : 0
+    const allowedMax = block.medianTime > CommonConstants.BLOCK_TX_CHAINING_ACTIVATION_MT ? CommonConstants.BLOCK_MAX_TX_CHAINING_DEPTH : 0
     if (max > allowedMax) {
       throw "The maximum transaction chaining length per block is " + CommonConstants.BLOCK_MAX_TX_CHAINING_DEPTH
     }
diff --git a/test/fast/modules/common/grammar.ts b/test/fast/modules/common/grammar.ts
index ebae873b89bce665f96040afa9061486b58d1868..198e3ee4051f64fd76d954204f43d3a1e5b0dd38 100644
--- a/test/fast/modules/common/grammar.ts
+++ b/test/fast/modules/common/grammar.ts
@@ -23,6 +23,10 @@ describe('Grammar', () => {
   let Ha = "CA978112CA1BBDCAFAC231B39A23DC4DA786EFF8147C4E72B9807785AFEE48BB"
   let Hz = "594E519AE499312B29433B7DD8A97FF068DEFCBA9755B6D5D00E84C524D67B06"
 
+  it('EMPTY string should work (but not unlock)', () => {
+    assert.equal(unlock('', [], { sigs: [] }), null)
+  })
+
   it('SIG should work', () => {
     assert.equal(unlock('SIG(' + k1 + ')', ['SIG(0)'], { sigs: [{ k:k1, ok:true }] }), true)
     assert.equal(unlock('SIG(' + k1 + ')', ['SIG(0)'], { sigs: [{ k:k1, ok:false }] }), null)
diff --git a/test/integration/fork-resolution/block-with-transaction-revert.ts b/test/integration/fork-resolution/block-with-transaction-revert.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ddf726fc6b1d662022fee075aa78943a9795ed90
--- /dev/null
+++ b/test/integration/fork-resolution/block-with-transaction-revert.ts
@@ -0,0 +1,135 @@
+// Source file from duniter: Crypto-currency software to manage libre currency such as Äž1
+// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+
+import {assertEqual, assertNull, writeBasicTestWithConfAnd2Users} from "../tools/test-framework"
+import {DBWallet} from "../../../app/lib/db/DBWallet"
+import {DBBlock} from "../../../app/lib/db/DBBlock"
+import {CommonConstants} from "../../../app/lib/common-libs/constants"
+import {TestUser} from "../tools/TestUser"
+import {TestingServer} from "../tools/toolbox"
+
+describe('Block revert with transaction sources', () => writeBasicTestWithConfAnd2Users({
+  dt: 10,
+  udTime0: CommonConstants.BLOCK_TX_CHAINING_ACTIVATION_MT + 10,
+  ud0: 1000,
+  switchOnHeadAdvance: 0,
+}, (test) => {
+
+  const now = CommonConstants.BLOCK_TX_CHAINING_ACTIVATION_MT
+
+  test('(b#1) should init with a Dividend at block#1', async (s1, cat, tac, toc) => {
+    await cat.createIdentity()
+    await tac.createIdentity()
+    await cat.cert(tac)
+    await tac.cert(cat)
+    await cat.join()
+    await tac.join()
+    await s1.commit({ time: now + 11 })
+    await s1.commit({ time: now + 11 })
+    await assertBlock1(s1, cat, tac, toc)
+  })
+
+  test('(b#2) tac sends to both tac and toc', async (s1, cat, tac, toc) => {
+    // Using transaction chaining to also test this case
+    const current = await s1._server.dal.getCurrentBlockOrNull() as DBBlock
+    const tx1 = await cat.prepareITX(1000, cat)
+    const tx2 = await cat.prepareUTX(tx1, ['SIG(0)'],
+      [
+        { qty: 100, base: 0, lock: 'SIG(' + tac.pub + ')' },
+        { qty: 200, base: 0, lock: 'SIG(' + toc.pub + ')' }, // Send money also to toc, to test that his money is ketp safe during a revert
+        { qty: 700, base: 0, lock: 'SIG(' + cat.pub + ')' }, // REST
+      ],
+      {
+        comment: 'CHAINED TX to 2 recipients', blockstamp: [current.number, current.hash].join('-')
+      }
+    )
+    await cat.sendTX(tx1)
+    await cat.sendTX(tx2)
+
+    await s1.commit({ time: now + 11 })
+    await assertBlock2(s1, cat, tac, toc)
+  })
+
+  test('(b#3) tac gives all to cat', async (s1, cat, tac, toc) => {
+    await tac.sendMoney(1100, cat)
+    await s1.commit({ time: now + 11 })
+    await assertBlock3(s1, cat, tac, toc)
+  })
+
+  test('(b#4) toc spends some received money', async (s1, cat, tac, toc) => {
+    // Using normal transaction
+    await toc.sendMoney(100, cat)
+    await s1.commit({ time: now + 11 })
+    await assertBlock4(s1, cat, tac, toc)
+  })
+
+  test('revert b#3-4 and re-commit block#3 should be ok', async (s1, cat, tac, toc) => {
+    await s1.revert()
+    await s1.revert()
+    await s1.resolve(b => b.number === 3)
+    await assertBlock3(s1, cat, tac, toc)
+  })
+
+  test('re-commit block#4 should be ok', async (s1, cat, tac, toc) => {
+    await s1.resolve(b => b.number === 4)
+    await assertBlock4(s1, cat, tac, toc)
+  })
+}))
+
+async function assertBlock1(s1: TestingServer, cat: TestUser, tac: TestUser, toc: TestUser) {
+  assertEqual((await s1._server.dal.dividendDAL.getUDSources(cat.pub)).length, 1)
+  assertEqual((await s1._server.dal.dividendDAL.getUDSources(tac.pub)).length, 1)
+  assertEqual((await s1._server.dal.dividendDAL.getUDSources(toc.pub)).length, 0) // toc is not a member
+  assertEqual((await s1._server.dal.sindexDAL.getAvailableForPubkey(cat.pub)).length, 0)
+  assertEqual((await s1._server.dal.sindexDAL.getAvailableForPubkey(tac.pub)).length, 0)
+  assertEqual((await s1._server.dal.sindexDAL.getAvailableForPubkey(toc.pub)).length, 0)
+  assertEqual((await s1._server.dal.walletDAL.getWallet('SIG(' + cat.pub + ')') as DBWallet).balance, 1000)
+  assertEqual((await s1._server.dal.walletDAL.getWallet('SIG(' + tac.pub + ')') as DBWallet).balance, 1000)
+  assertNull(await s1._server.dal.walletDAL.getWallet('SIG(' + toc.pub + ')'))
+}
+
+async function assertBlock2(s1: TestingServer, cat: TestUser, tac: TestUser, toc: TestUser) {
+  assertEqual((await s1._server.dal.dividendDAL.getUDSources(cat.pub)).length, 0) // <-- The UD gets consumed
+  assertEqual((await s1._server.dal.dividendDAL.getUDSources(tac.pub)).length, 1)
+  assertEqual((await s1._server.dal.dividendDAL.getUDSources(toc.pub)).length, 0) // toc is not a member
+  assertEqual((await s1._server.dal.sindexDAL.getAvailableForPubkey(cat.pub)).length, 1)
+  assertEqual((await s1._server.dal.sindexDAL.getAvailableForPubkey(tac.pub)).length, 1)
+  assertEqual((await s1._server.dal.sindexDAL.getAvailableForPubkey(toc.pub)).length, 1)
+  assertEqual((await s1._server.dal.walletDAL.getWallet('SIG(' + cat.pub + ')') as DBWallet).balance, 700) // <-- -300 here
+  assertEqual((await s1._server.dal.walletDAL.getWallet('SIG(' + tac.pub + ')') as DBWallet).balance, 1100) // <-- +100 here
+  assertEqual((await s1._server.dal.walletDAL.getWallet('SIG(' + toc.pub + ')') as DBWallet).balance, 200) // <-- +200 here
+}
+
+async function assertBlock3(s1: TestingServer, cat: TestUser, tac: TestUser, toc: TestUser) {
+  assertEqual((await s1._server.dal.dividendDAL.getUDSources(cat.pub)).length, 0)
+  assertEqual((await s1._server.dal.dividendDAL.getUDSources(tac.pub)).length, 0) // <-- The UD gets consumed
+  assertEqual((await s1._server.dal.dividendDAL.getUDSources(toc.pub)).length, 0) // toc is not a member
+  assertEqual((await s1._server.dal.sindexDAL.getAvailableForPubkey(cat.pub)).length, 2) // <-- Cat receives a new source
+  assertEqual((await s1._server.dal.sindexDAL.getAvailableForPubkey(tac.pub)).length, 0) // <-- Every TX source gets consumed
+  assertEqual((await s1._server.dal.sindexDAL.getAvailableForPubkey(toc.pub)).length, 1)
+  assertEqual((await s1._server.dal.walletDAL.getWallet('SIG(' + cat.pub + ')') as DBWallet).balance, 1800) // <-- +1100 here
+  assertEqual((await s1._server.dal.walletDAL.getWallet('SIG(' + tac.pub + ')') as DBWallet).balance, 0) // <-- -1100 here
+  assertEqual((await s1._server.dal.walletDAL.getWallet('SIG(' + toc.pub + ')') as DBWallet).balance, 200)
+}
+
+async function assertBlock4(s1: TestingServer, cat: TestUser, tac: TestUser, toc: TestUser) {
+  assertEqual((await s1._server.dal.dividendDAL.getUDSources(cat.pub)).length, 0)
+  assertEqual((await s1._server.dal.dividendDAL.getUDSources(tac.pub)).length, 0)
+  assertEqual((await s1._server.dal.dividendDAL.getUDSources(toc.pub)).length, 0) // toc is not a member
+  assertEqual((await s1._server.dal.sindexDAL.getAvailableForPubkey(cat.pub)).length, 3) // <-- Cat receives a new source
+  assertEqual((await s1._server.dal.sindexDAL.getAvailableForPubkey(tac.pub)).length, 0)
+  assertEqual((await s1._server.dal.sindexDAL.getAvailableForPubkey(toc.pub)).length, 1) // <-- Consume everything + Create a rest
+  assertEqual((await s1._server.dal.walletDAL.getWallet('SIG(' + cat.pub + ')') as DBWallet).balance, 1900)// <-- +100 here
+  assertEqual((await s1._server.dal.walletDAL.getWallet('SIG(' + tac.pub + ')') as DBWallet).balance, 0)
+  assertEqual((await s1._server.dal.walletDAL.getWallet('SIG(' + toc.pub + ')') as DBWallet).balance, 100)// <-- -100 here
+}