diff --git a/app/lib/blockchain/DuniterBlockchain.ts b/app/lib/blockchain/DuniterBlockchain.ts index af3cbbc68febd192b9fb8d9fdd9dea865e9e62ed..0b446a7375ca4d8fe4daa701f28e86eb54edbe34 100644 --- a/app/lib/blockchain/DuniterBlockchain.ts +++ b/app/lib/blockchain/DuniterBlockchain.ts @@ -213,15 +213,15 @@ export class DuniterBlockchain extends MiscIndexedBlockchain { const TAIL = await dal.bindexDAL.tail(); const bindexSize = [ - block.issuersCount, - block.issuersFrame, + TAIL.issuersCount, + TAIL.issuersFrame, conf.medianTimeBlocks, conf.dtDiffEval ].reduce((max, value) => { return Math.max(max, value); }, 0); - const MAX_BINDEX_SIZE = 2 * bindexSize; - const currentSize = indexes.HEAD.number - TAIL.number + 1; + const MAX_BINDEX_SIZE = conf.forksize + bindexSize + const currentSize = indexes.HEAD.number - TAIL.number + 1 if (currentSize > MAX_BINDEX_SIZE) { await dal.trimIndexes(indexes.HEAD.number - MAX_BINDEX_SIZE); } diff --git a/app/lib/blockchain/Switcher.ts b/app/lib/blockchain/Switcher.ts index 1bf69f0088ac27da8dafd542812140f2fb2d0214..e6ae9892390d004a2c4455f077cb87c5e56612f6 100644 --- a/app/lib/blockchain/Switcher.ts +++ b/app/lib/blockchain/Switcher.ts @@ -21,6 +21,7 @@ export class Switcher<T extends SwitchBlock> { constructor( private dao:SwitcherDao<T>, + private invalidForks:string[], private avgGenTime:number, private forkWindowSize:number, private switchOnHeadAdvance:number, @@ -36,7 +37,7 @@ export class Switcher<T extends SwitchBlock> { const numberStart = current.number + this.switchOnHeadAdvance const timeStart = current.medianTime + this.switchOnHeadAdvance * this.avgGenTime // Phase 1: find potential chains - const suites = await this.findPotentialSuites(current, numberStart, timeStart) + const suites = await this.findPotentialSuites(numberStart, timeStart) if (suites.length) { this.logger && this.logger.info("Fork resolution: %s potential suite(s) found...", suites.length) } @@ -62,19 +63,18 @@ export class Switcher<T extends SwitchBlock> { async findPotentialSuitesHeads(current:T) { const numberStart = current.number - this.forkWindowSize const timeStart = current.medianTime - this.forkWindowSize * this.avgGenTime - const suites = await this.findPotentialSuites(current, numberStart, timeStart) + const suites = await this.findPotentialSuites(numberStart, timeStart) return suites.map(suite => suite[suite.length - 1]) } /** * Looks at the potential blocks that could form fork chains in the sandbox, and sort them to have a maximum of unique * chains. - * @param {SwitchBlock} current HEAD of local blockchain. * @param numberStart The minimum number of a fork block. * @param timeStart The minimum medianTime of a fork block. * @returns {SwitchBlock[][]} The suites found. */ - private async findPotentialSuites(current:T, numberStart:number, timeStart:number) { + private async findPotentialSuites(numberStart:number, timeStart:number) { const suites:T[][] = [] const potentials:T[] = await this.dao.getPotentials(numberStart, timeStart, numberStart + this.forkWindowSize) const knownForkBlocks:{ [k:string]: boolean } = {} @@ -115,6 +115,12 @@ export class Switcher<T extends SwitchBlock> { previous = await this.dao.getSandboxBlock(previousNumber, previousHash) if (previous) { knownForkBlocks[BlockDTO.fromJSONObject(previous).blockstamp] = true + const alreadyKnownInvalidBlock = this.invalidForks.indexOf([previous.number, previous.hash].join('-')) !== -1 + if (alreadyKnownInvalidBlock) { + // Incorrect = not found + this.logger && this.logger.info("Fork resolution: block #%s-%s is known as incorrect. Skipping.", previous.number, previous.hash.substr(0, 8)) + previous = null + } } } } @@ -164,6 +170,7 @@ export class Switcher<T extends SwitchBlock> { this.logger && this.logger.info("Fork resolution: suite %s/%s added block#%s-%s", j, suites.length, s[i].number, s[i].hash) successfulBlocks.push(s[i]) } catch (e) { + this.invalidForks.push([s[i].number, s[i].hash].join('-')) this.logger && this.logger.info("Fork resolution: suite %s/%s REFUSED block#%s: %s", j, suites.length, s[0].number + i, e && e.message) added = false } @@ -171,6 +178,9 @@ export class Switcher<T extends SwitchBlock> { } // Pop the successfuly added blocks if (successfulBlocks.length) { + for (const b of successfulBlocks) { + this.invalidForks.push([b.number, b.hash].join('-')) + } const addedToHeadLevel = successfulBlocks[successfulBlocks.length-1].number - current.number this.logger && this.logger.info("Fork resolution: suite %s/%s reached HEAD + %s. Now rolling back.", j, suites.length, addedToHeadLevel) await this.dao.revertTo(forkPoint) diff --git a/app/lib/computation/BlockchainContext.ts b/app/lib/computation/BlockchainContext.ts index 35be72791a1dfbfdf5f91042272a90690b5f6ba3..426ed2dc8c8b0bfcca4ccd6b6c37bee22d58ab1b 100644 --- a/app/lib/computation/BlockchainContext.ts +++ b/app/lib/computation/BlockchainContext.ts @@ -157,7 +157,7 @@ export class BlockchainContext { } } - quickApplyBlocks(blocks:BlockDTO[], to: number | null): Promise<any> { + quickApplyBlocks(blocks:BlockDTO[], to: number): Promise<any> { return this.quickSynchronizer.quickApplyBlocks(blocks, to) } } diff --git a/app/lib/computation/QuickSync.ts b/app/lib/computation/QuickSync.ts index 1047aeda6980129863794dfd8ed0485f36fb7454..038740eb783966a31dc57680471ba183c47e3afa 100644 --- a/app/lib/computation/QuickSync.ts +++ b/app/lib/computation/QuickSync.ts @@ -1,9 +1,9 @@ "use strict" -import {DuniterBlockchain} from "../blockchain/DuniterBlockchain" -import {BlockDTO} from "../dto/BlockDTO" -import {DBTransaction} from "../db/DBTransaction" -import {Indexer} from "../indexer" -import {CurrencyConfDTO} from "../dto/ConfDTO" +import {DuniterBlockchain} from "../blockchain/DuniterBlockchain"; +import {BlockDTO} from "../dto/BlockDTO"; +import {DBTransaction} from "../db/DBTransaction"; +import {Indexer} from "../indexer"; +import {CurrencyConfDTO} from "../dto/ConfDTO"; const _ = require('underscore') const constants = require('../constants') @@ -88,7 +88,7 @@ export class QuickSynchronizer { return this.dal.updateTransactions(txs); } - async quickApplyBlocks(blocks:BlockDTO[], to: number | null): Promise<void> { + async quickApplyBlocks(blocks:BlockDTO[], to: number): Promise<void> { sync_memoryDAL.sindexDAL = { getAvailableForConditions: (conditions:string) => this.dal.sindexDAL.getAvailableForConditions(conditions) } let blocksToSave: BlockDTO[] = []; @@ -103,7 +103,7 @@ export class QuickSynchronizer { sync_currConf = BlockDTO.getConf(block); } - if (block.number != to) { + if (block.number <= to - this.conf.forksize) { blocksToSave.push(dto); const index:any = Indexer.localIndex(dto, sync_currConf); const local_iindex = Indexer.iindex(index); @@ -203,7 +203,7 @@ export class QuickSynchronizer { } // Trim the bindex - sync_bindexSize = [ + sync_bindexSize = this.conf.forksize + [ block.issuersCount, block.issuersFrame, this.conf.medianTimeBlocks, @@ -239,6 +239,13 @@ export class QuickSynchronizer { 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) + for (const cond of conditions) { + delete sync_memoryWallets[cond] + } + + if (block.number === 0) { + await this.blockchain.saveParametersForRoot(block, this.conf, this.dal) + } // Last block: cautious mode to trigger all the INDEX expiry mechanisms const { index, HEAD } = await DuniterBlockchain.checkBlock(dto, constants.WITH_SIGNATURES_AND_POW, this.conf, this.dal) diff --git a/app/modules/prover/lib/permanentProver.ts b/app/modules/prover/lib/permanentProver.ts index 033fdb4c70ddad6fa270499ec3fc5525610d9549..f0c974bbf7cc7d6868ff40ef864fb2b14fab4c7b 100644 --- a/app/modules/prover/lib/permanentProver.ts +++ b/app/modules/prover/lib/permanentProver.ts @@ -156,11 +156,15 @@ export class PermanentProver { // The generation (async () => { try { - const current = await this.server.dal.getCurrentBlockOrNull(); - const selfPubkey = this.server.keyPair.publicKey; - const trial2 = await this.server.getBcContext().getIssuerPersonalizedDifficulty(selfPubkey); - this.checkTrialIsNotTooHigh(trial2, current, selfPubkey); - this.lastComputedBlock = await this.generator.makeNextBlock(null, trial2); + let unsignedBlock = null, trial2 = 0 + await this.server.BlockchainService.pushFIFO('generatingNextBlock', async () => { + const current = await this.server.dal.getCurrentBlockOrNull(); + const selfPubkey = this.server.keyPair.publicKey; + trial2 = await this.server.getBcContext().getIssuerPersonalizedDifficulty(selfPubkey); + this.checkTrialIsNotTooHigh(trial2, current, selfPubkey); + unsignedBlock = await this.generator.nextBlock() + }) + this.lastComputedBlock = await this.prover.prove(unsignedBlock, trial2, null) try { const obj = parsers.parseBlock.syncWrite(dos2unix(this.lastComputedBlock.getRawSigned())); await this.server.writeBlock(obj) diff --git a/app/service/BlockchainService.ts b/app/service/BlockchainService.ts index 2735bb16f886dae63036b19bb082f50c5bb8369a..fe69db9e998fdab69f71cedb37d9bdeb83cd41c1 100644 --- a/app/service/BlockchainService.ts +++ b/app/service/BlockchainService.ts @@ -28,6 +28,7 @@ export class BlockchainService extends FIFOService { selfPubkey:string quickSynchronizer:QuickSynchronizer switcherDao:SwitcherDao<BlockDTO> + invalidForks:string[] = [] constructor(private server:any, fifoPromiseHandler:GlobalFifoPromise) { super(fifoPromiseHandler) @@ -119,7 +120,7 @@ export class BlockchainService extends FIFOService { async branches() { const current = await this.current() - const switcher = new Switcher(this.switcherDao, this.conf.avgGenTime, this.conf.forksize, this.conf.switchOnHeadAdvance, this.logger) + const switcher = new Switcher(this.switcherDao, this.invalidForks, this.conf.avgGenTime, this.conf.forksize, this.conf.switchOnHeadAdvance, this.logger) const heads = await switcher.findPotentialSuitesHeads(current) return heads.concat([current]) } @@ -197,6 +198,8 @@ export class BlockchainService extends FIFOService { bcEvent: OtherConstants.BC_EVENT.HEAD_CHANGED, block: addedBlock }) + // Clear invalid forks' cache + this.invalidForks.splice(0, this.invalidForks.length) } catch (e) { this.logger.error(e) added = false @@ -210,7 +213,7 @@ export class BlockchainService extends FIFOService { } async forkResolution() { - const switcher = new Switcher(this.switcherDao, this.conf.avgGenTime, this.conf.forksize, this.conf.switchOnHeadAdvance, this.logger) + const switcher = new Switcher(this.switcherDao, this.invalidForks, this.conf.avgGenTime, this.conf.forksize, this.conf.switchOnHeadAdvance, this.logger) const newCurrent = await switcher.tryToFork() if (newCurrent) { this.push({ @@ -399,7 +402,7 @@ export class BlockchainService extends FIFOService { * @param blocks An array of blocks to insert. * @param to The final block number of the fast insertion. */ - fastBlockInsertions(blocks:BlockDTO[], to:number | null) { + fastBlockInsertions(blocks:BlockDTO[], to:number) { return this.mainContext.quickApplyBlocks(blocks, to) } } diff --git a/gui/index.html b/gui/index.html index ef2629ed9066f74bf6f1c851ba4a51e6d805fa29..3e8593d3b3e38d4524c99e04fef9e0d8006cc89f 100644 --- a/gui/index.html +++ b/gui/index.html @@ -3,7 +3,7 @@ <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <title>Duniter 1.5.6</title> + <title>Duniter 1.5.9</title> <style> html { font-family: "Courier New", Courier, monospace; diff --git a/package.json b/package.json index 96a085f109e458de7f352acd30e0ee7a429767c4..b14f760bf8a72d79e886997d4bf30ad969828861 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "duniter", - "version": "1.5.6", + "version": "1.5.9", "engines": { "node": ">=6.11.1", "npm": ">=3.10" @@ -12,7 +12,7 @@ "node-main": "./bin/duniter", "window": { "icon": "duniter.png", - "title": "v1.5.6", + "title": "v1.5.9", "width": 800, "height": 800, "min_width": 750, diff --git a/release/arch/debian/package/DEBIAN/control b/release/arch/debian/package/DEBIAN/control index 8481999bfa2e07fdebb6dcfde17d75312cf5f3ee..6ab95677dbf44142488ef97dfd340a8a480ef69e 100644 --- a/release/arch/debian/package/DEBIAN/control +++ b/release/arch/debian/package/DEBIAN/control @@ -1,5 +1,5 @@ Package: duniter -Version: 1.5.6 +Version: 1.5.9 Section: misc Priority: optional Architecture: all diff --git a/release/arch/windows/duniter.iss b/release/arch/windows/duniter.iss index 5e5c35d35f7feda6b6f9206460b9e0ba9edf6ce3..a92d22bdbb7ec94c2344aeadee9430bd288dc325 100644 --- a/release/arch/windows/duniter.iss +++ b/release/arch/windows/duniter.iss @@ -15,7 +15,7 @@ #error "Unable to find MyAppExe" #endif -#define MyAppVerStr "v1.5.6" +#define MyAppVerStr "v1.5.9" [Setup] AppName={#MyAppName} diff --git a/test/dal/triming.js b/test/dal/triming.js index 114decf96c45caf5239bfbd6e69665a4a0cf2865..db2c0cb849343c53b7db558a368729cf7185b440 100644 --- a/test/dal/triming.js +++ b/test/dal/triming.js @@ -128,6 +128,7 @@ describe("Triming", function(){ pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP' }, + forksize: 9, sigQty: 1, dtDiffEval: 2, medianTimeBlocks: 3 diff --git a/test/fast/fork-resolution-3-3.ts b/test/fast/fork-resolution-3-3.ts index 2a8e3215b17a17578827195493d58b4ce26b14cf..fc9a64a2b43d84e4fb92fcf62fbae81358920118 100644 --- a/test/fast/fork-resolution-3-3.ts +++ b/test/fast/fork-resolution-3-3.ts @@ -1,4 +1,4 @@ -import * as assert from 'assert' +import * as assert from "assert" import {SwitchBlock, Switcher, SwitcherDao} from "../../app/lib/blockchain/Switcher" import {NewLogger} from "../../app/lib/logger" @@ -27,7 +27,7 @@ describe("Fork resolution 3-3 algo", () => { Block.from("C15"), Block.from("C16") ]) - const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), avgGenTime, forkWindowSize, switchOnHeadAdvance, logger) + const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), [], avgGenTime, forkWindowSize, switchOnHeadAdvance, logger) await switcher.tryToFork() assert.equal(bc.current.number, 16) assert.equal(bc.current.hash, "C16") @@ -49,7 +49,7 @@ describe("Fork resolution 3-3 algo", () => { Block.from("C14"), Block.from("C15") ]) - const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), avgGenTime, forkWindowSize, switchOnHeadAdvance) + const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), [], avgGenTime, forkWindowSize, switchOnHeadAdvance) await switcher.tryToFork() assert.equal(bc.current.number, 13) assert.equal(bc.current.hash, "B13") @@ -69,7 +69,7 @@ describe("Fork resolution 3-3 algo", () => { Block.from("C14"), Block.from("C15") ]) - const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), avgGenTime, forkWindowSize, switchOnHeadAdvance) + const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), [], avgGenTime, forkWindowSize, switchOnHeadAdvance) await switcher.tryToFork() assert.equal(bc.current.number, 13) assert.equal(bc.current.hash, "B13") @@ -94,7 +94,7 @@ describe("Fork resolution 3-3 algo", () => { Block.from("C15"), Block.from("C16") ]) - const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), avgGenTime, forkWindowSize, switchOnHeadAdvance) + const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), [], avgGenTime, forkWindowSize, switchOnHeadAdvance) await switcher.tryToFork() assert.equal(bc.current.number, 13) assert.equal(bc.current.hash, "B13") @@ -118,7 +118,7 @@ describe("Fork resolution 3-3 algo", () => { Block.from("C15"), Block.from("C16") ]) - const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), avgGenTime, forkWindowSize, switchOnHeadAdvance) + const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), [], avgGenTime, forkWindowSize, switchOnHeadAdvance) await switcher.tryToFork() assert.equal(bc.current.number, 13) assert.equal(bc.current.hash, "B13") @@ -141,7 +141,7 @@ describe("Fork resolution 3-3 algo", () => { Block.from("C15"), Block.from("C16") ]) - const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), avgGenTime, forkWindowSize, switchOnHeadAdvance) + const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), [], avgGenTime, forkWindowSize, switchOnHeadAdvance) await switcher.tryToFork() assert.equal(bc.current.number, 13) assert.equal(bc.current.hash, "B13") @@ -170,7 +170,7 @@ describe("Fork resolution 3-3 algo", () => { Block.from("E14"), Block.from("E15") ]) - const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), avgGenTime, forkWindowSize, 1) + const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), [], avgGenTime, forkWindowSize, 1) await switcher.tryToFork() assert.equal(16, bc.current.number) assert.equal("D16", bc.current.hash) diff --git a/test/integration/branches.js b/test/integration/branches.js index 9372747a4c548ef345b950b80483d4683cfcc564..a7700cfbbba75924734d75c662ba465cdd002e64 100644 --- a/test/integration/branches.js +++ b/test/integration/branches.js @@ -51,7 +51,7 @@ describe("Branches", () => co(function*() { it('should have a 3 blocks fork window size', function() { return expectAnswer(rp('http://127.0.0.1:7778/node/summary', { json: true }), function(res) { res.should.have.property('duniter').property('software').equal('duniter'); - res.should.have.property('duniter').property('version').equal('1.5.6'); + res.should.have.property('duniter').property('version').equal('1.5.9'); res.should.have.property('duniter').property('forkWindowSize').equal(3); }); });