From 5bedff1e636cb2112f53cf147787d6782a13119c Mon Sep 17 00:00:00 2001
From: cgeek <cem.moreau@gmail.com>
Date: Sat, 21 Jul 2018 11:27:03 +0200
Subject: [PATCH] [fix] dal: `getBlocks` function was broken if the chunk was
 targeting the archives

---
 app/lib/dal/fileDAL.ts                        | 21 +++++++-
 app/lib/dal/indexDAL/CFSBlockchainArchive.ts  | 53 ++++++++++++++++---
 .../indexDAL/abstract/BlockchainArchiveDAO.ts |  8 +++
 3 files changed, 73 insertions(+), 9 deletions(-)

diff --git a/app/lib/dal/fileDAL.ts b/app/lib/dal/fileDAL.ts
index 62e3799da..d4c0bb389 100644
--- a/app/lib/dal/fileDAL.ts
+++ b/app/lib/dal/fileDAL.ts
@@ -412,8 +412,25 @@ export class FileDAL {
     return this.blockDAL.getCountOfBlocksIssuedBy(issuer)
   }
 
-  getBlocksBetween (start:number, end:number) {
-    return this.blockDAL.getBlocks(Math.max(0, start), end)
+  async getBlocksBetween (start:number, end:number) {
+    start = Math.max(0, start)
+    end= Math.max(0, end)
+    const blocks = await this.blockDAL.getBlocks(Math.max(0, start), end)
+    if (blocks[0] && blocks[0].number === start) {
+      // OK: we have all the blocks from memory
+      return blocks
+    }
+    // Else: we have to pick them from archives
+    const last = blocks[0] ? blocks[0].number - 1 : end
+    const archiveBlocks = await this.blockchainArchiveDAL.getBlocks(start, last)
+    const lastInArchives = archiveBlocks[archiveBlocks.length - 1] ? archiveBlocks[archiveBlocks.length - 1].number - 1 : end
+    if (lastInArchives === end) {
+      // OK: we have all the blocks from archives
+      return archiveBlocks
+    }
+    // Otherwise: what is not taken in the archives are in memory
+    const memBlocks = await this.blockDAL.getBlocks(archiveBlocks[archiveBlocks.length - 1].number + 1, end)
+    return archiveBlocks.concat(memBlocks)
   }
 
   getForkBlocksFollowing(current:DBBlock) {
diff --git a/app/lib/dal/indexDAL/CFSBlockchainArchive.ts b/app/lib/dal/indexDAL/CFSBlockchainArchive.ts
index 361315590..44fb159e3 100644
--- a/app/lib/dal/indexDAL/CFSBlockchainArchive.ts
+++ b/app/lib/dal/indexDAL/CFSBlockchainArchive.ts
@@ -1,5 +1,6 @@
 import {BlockchainArchiveDAO, BlockLike} from "./abstract/BlockchainArchiveDAO"
 import {CFSCore} from "../fileDALs/CFSCore"
+import {Underscore} from "../../common-libs/underscore"
 
 export class CFSBlockchainArchive<T extends BlockLike> implements BlockchainArchiveDAO<T> {
 
@@ -15,7 +16,7 @@ export class CFSBlockchainArchive<T extends BlockLike> implements BlockchainArch
     }
     const chunks = this.splitIntoChunks(records)
     for (const c of chunks) {
-      const fileName = this.getFileName(c[0].number)
+      const fileName = this.getFileNameForBlock(c[0].number)
       await this.cfs.writeJSON(fileName, c)
     }
     return chunks.length
@@ -62,7 +63,7 @@ export class CFSBlockchainArchive<T extends BlockLike> implements BlockchainArch
     if (number < 0) {
       return null
     }
-    const content = await this.getChunk(number)
+    const content = await this.getChunkForBlock(number)
     if (!content) {
       // The block's chunk is not archived
       return null
@@ -70,8 +71,38 @@ export class CFSBlockchainArchive<T extends BlockLike> implements BlockchainArch
     return content[this.getPositionInChunk(number)]
   }
 
+  async getBlocks(start: number, end: number): Promise<T[]> {
+    const chunkStart = this.getChunkNumber(start)
+    const chunkLast = this.getChunkNumber(end)
+    const chunkRange = Underscore.range(chunkStart, chunkLast + 1)
+    const chunks = await Promise.all(chunkRange.map(c => this.getChunk(c)))
+    const startInFirst = start - chunkStart * this._chunkSize
+    const endInLast = end % this._chunkSize + 1
+    let blocks: T[] = []
+    for (let i = 0; i < chunks.length; i++) {
+      let toConcat: T[] = []
+      const chunk = chunks[i]
+      if (chunk) {
+        if (i === 0) {
+          toConcat = chunk.slice(startInFirst, chunkStart === chunkLast ? endInLast : this._chunkSize)
+        } else if (i === chunks.length - 1) {
+          toConcat = chunk.slice(0, endInLast)
+        } else {
+          toConcat = chunk.slice()
+        }
+      }
+      blocks = blocks.concat(toConcat)
+    }
+    return blocks
+  }
+
   async getChunk(number:number): Promise<(T[])|null> {
-    const file = this.getFileName(number)
+    const file = this.getFileNameForChunk(number)
+    return this.cfs.readJSON(file)
+  }
+
+  async getChunkForBlock(number:number): Promise<(T[])|null> {
+    const file = this.getFileNameForBlock(number)
     return this.cfs.readJSON(file)
   }
 
@@ -84,19 +115,27 @@ export class CFSBlockchainArchive<T extends BlockLike> implements BlockchainArch
       .reduce((v, max) => {
         return Math.max(v, max)
       }, 0)
-    const content = await this.getChunk(max * this._chunkSize)
+    const content = await this.getChunkForBlock(max * this._chunkSize)
     if (!content) {
       return null
     }
     return this.getBlock(content[content.length - 1].number, content[content.length - 1].hash)
   }
 
-  private getFileName(number:number) {
-    const rest = number % this._chunkSize
-    const chunk = (number - rest) / this._chunkSize
+  private getFileNameForChunk(number:number) {
+    return CFSBlockchainArchive.getChunkName(number, this._chunkSize)
+  }
+
+  private getFileNameForBlock(number:number) {
+    const chunk = this.getChunkNumber(number)
     return CFSBlockchainArchive.getChunkName(chunk, this._chunkSize)
   }
 
+  private getChunkNumber(number:number) {
+    const rest = number % this._chunkSize
+    return (number - rest) / this._chunkSize
+  }
+
   private static getChunkName(chunkNumber:number, chunkSize:number) {
     return `chunk_${chunkNumber}-${chunkSize}.json`
   }
diff --git a/app/lib/dal/indexDAL/abstract/BlockchainArchiveDAO.ts b/app/lib/dal/indexDAL/abstract/BlockchainArchiveDAO.ts
index 123c169ea..59e655c36 100644
--- a/app/lib/dal/indexDAL/abstract/BlockchainArchiveDAO.ts
+++ b/app/lib/dal/indexDAL/abstract/BlockchainArchiveDAO.ts
@@ -29,6 +29,14 @@ export interface BlockchainArchiveDAO<T extends BlockLike> extends Initiable {
    */
   getBlockByNumber(number:number): Promise<T|null>
 
+  /**
+   * Get the blocks whose number is between [start ; end].
+   * @param {number} start Starting number to be included.
+   * @param {number} end Ending number to be included.
+   * @returns {Promise<T[]>} The corresponding blocks.
+   */
+  getBlocks(start: number, end: number): Promise<T[]>
+
   /**
    * Archives a suite of blocks.
    *
-- 
GitLab