From 3080f306771df7ee97e7ac3a78af6fbd84a54332 Mon Sep 17 00:00:00 2001 From: cgeek <cem.moreau@gmail.com> Date: Sat, 5 Aug 2017 15:00:04 +0200 Subject: [PATCH] [fix] #1005 Fork blocks are now accepted in the same flow as normal blocks --- app/lib/blockchain/DuniterBlockchain.ts | 8 +- app/lib/common-libs/constants.ts | 4 + app/lib/computation/BlockchainContext.ts | 7 +- app/lib/dal/fileDALs/ConfDAL.ts | 4 +- app/lib/dto/BlockDTO.ts | 1 + app/lib/dto/ConfDTO.ts | 9 +- .../bma/lib/controllers/AbstractController.ts | 3 + app/modules/crawler/index.ts | 9 - app/modules/crawler/lib/constants.ts | 1 - app/modules/crawler/lib/pulling.ts | 12 +- app/service/BlockchainService.ts | 35 +-- server.ts | 3 +- test/fast/modules/crawler/block_pulling.ts | 2 +- test/integration/branches2.js | 8 +- test/integration/branches_switch.js | 4 +- test/integration/register-fork-blocks.js | 209 ++++++++++++++++++ test/integration/tools/toolbox.ts | 2 +- 17 files changed, 270 insertions(+), 51 deletions(-) create mode 100644 test/integration/register-fork-blocks.js diff --git a/app/lib/blockchain/DuniterBlockchain.ts b/app/lib/blockchain/DuniterBlockchain.ts index 0eba64c44..a8f651f21 100644 --- a/app/lib/blockchain/DuniterBlockchain.ts +++ b/app/lib/blockchain/DuniterBlockchain.ts @@ -56,7 +56,9 @@ export class DuniterBlockchain extends MiscIndexedBlockchain { // BR_G56 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'); // BR_G59 @@ -269,7 +271,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain { conf.udTime0 = bconf.udTime0; conf.udReevalTime0 = bconf.udReevalTime0; conf.dtReeval = bconf.dtReeval; - conf.currency = block.currency; + conf.currency = bconf.currency; // Super important: adapt wotb module to handle the correct stock dal.wotb.setMaxCert(conf.sigStock); return dal.saveConf(conf); @@ -516,7 +518,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain { // Saves the block (DAL) block.wrong = false; await dal.saveSideBlockInFile(block); - logger.info('SIDE Block #' + block.number + ' added to the blockchain in %s ms', (Date.now() - start)); + logger.info('SIDE Block #%s-%s added to the blockchain in %s ms', block.number, block.hash.substr(0, 8), (Date.now() - start)); return block; } catch (err) { throw err; diff --git a/app/lib/common-libs/constants.ts b/app/lib/common-libs/constants.ts index 9136da34b..9a0d889b6 100644 --- a/app/lib/common-libs/constants.ts +++ b/app/lib/common-libs/constants.ts @@ -73,6 +73,8 @@ export const CommonConstants = { DOCUMENTS_VERSION: 10, TRANSACTION_MAX_TRIES: 10, + SWITCH_ON_BRANCH_AHEAD_BY_X_BLOCKS: 6, + BMA_REGEXP, PUBLIC_KEY: exact(PUBKEY), INTEGER: /^\d+$/, @@ -113,6 +115,8 @@ export const CommonConstants = { ] }, + DocumentError: "documentError", + ERRORS: { // Technical errors WRONG_DOCUMENT: { httpCode: 400, uerr: { ucode: 1005, message: "Document has unkown fields or wrong line ending format" }}, diff --git a/app/lib/computation/BlockchainContext.ts b/app/lib/computation/BlockchainContext.ts index 3237e0215..43a9a2a4b 100644 --- a/app/lib/computation/BlockchainContext.ts +++ b/app/lib/computation/BlockchainContext.ts @@ -100,7 +100,7 @@ export class BlockchainContext { this.logger = require('../logger').NewLogger(this.dal.profile); } - checkBlock(block: BlockDTO, withPoWAndSignature = true): Promise<any> { + checkBlock(block: BlockDTO, withPoWAndSignature:boolean): Promise<any> { return DuniterBlockchain.checkBlock(block, withPoWAndSignature, this.conf, this.dal) } @@ -110,8 +110,9 @@ export class BlockchainContext { return block } - addSideBlock(obj:BlockDTO): Promise<any> { - return this.blockchain.pushSideBlock(obj, this.dal, this.logger) + async addSideBlock(obj:BlockDTO): Promise<BlockDTO> { + const dbb = await this.blockchain.pushSideBlock(obj, this.dal, this.logger) + return dbb.toBlockDTO() } async revertCurrentBlock(): Promise<any> { diff --git a/app/lib/dal/fileDALs/ConfDAL.ts b/app/lib/dal/fileDALs/ConfDAL.ts index 494f86de4..ff5a0e707 100644 --- a/app/lib/dal/fileDALs/ConfDAL.ts +++ b/app/lib/dal/fileDALs/ConfDAL.ts @@ -1,5 +1,6 @@ import {AbstractCFS} from "./AbstractCFS" import {ConfDTO} from "../../dto/ConfDTO" +import {CommonConstants} from "../../common-libs/constants"; const _ = require('underscore'); @@ -39,7 +40,8 @@ export class ConfDAL extends AbstractCFS { "percentRot": parseFloat(conf.percentRot), "udTime0": parseInt(conf.udTime0), "udReevalTime0": parseInt(conf.udReevalTime0), - "dtReeval": parseInt(conf.dtReeval) + "dtReeval": parseInt(conf.dtReeval), + "switchOnHeadAdvance": CommonConstants.SWITCH_ON_BRANCH_AHEAD_BY_X_BLOCKS } } diff --git a/app/lib/dto/BlockDTO.ts b/app/lib/dto/BlockDTO.ts index 756661ecc..6b982787a 100644 --- a/app/lib/dto/BlockDTO.ts +++ b/app/lib/dto/BlockDTO.ts @@ -232,6 +232,7 @@ export class BlockDTO implements Cloneable { static getConf(block:BlockDTO): CurrencyConfDTO { const sp = block.parameters.split(':'); return { + currency: block.currency, c: parseFloat(sp[0]), dt: parseInt(sp[1]), ud0: parseInt(sp[2]), diff --git a/app/lib/dto/ConfDTO.ts b/app/lib/dto/ConfDTO.ts index 7b2a9777d..40f4ad2b6 100644 --- a/app/lib/dto/ConfDTO.ts +++ b/app/lib/dto/ConfDTO.ts @@ -1,3 +1,4 @@ +import {CommonConstants} from "../common-libs/constants"; const _ = require('underscore'); const constants = require('../constants'); @@ -7,12 +8,13 @@ export interface Keypair { } export interface BranchingDTO { - swichOnTimeAheadBy:number + switchOnHeadAdvance:number avgGenTime:number forksize:number } export interface CurrencyConfDTO { + currency: string c: number dt: number ud0: number @@ -96,7 +98,7 @@ export class ConfDTO implements CurrencyConfDTO, KeypairConfDTO, NetworkConfDTO, public idtyWindow: number, public msWindow: number, public sigWindow: number, - public swichOnTimeAheadBy: number, + public switchOnHeadAdvance: number, public pair: Keypair, public oldPair: Keypair|null, public salt: string, @@ -143,7 +145,8 @@ export class ConfDTO implements CurrencyConfDTO, KeypairConfDTO, NetworkConfDTO, "udid2": false, "timeout": 3000, "isolate": false, - "forksize": constants.BRANCHES.DEFAULT_WINDOW_SIZE + "forksize": constants.BRANCHES.DEFAULT_WINDOW_SIZE, + "switchOnHeadAdvance": CommonConstants.SWITCH_ON_BRANCH_AHEAD_BY_X_BLOCKS }; } diff --git a/app/modules/bma/lib/controllers/AbstractController.ts b/app/modules/bma/lib/controllers/AbstractController.ts index 1b3a6d2cb..048a292eb 100644 --- a/app/modules/bma/lib/controllers/AbstractController.ts +++ b/app/modules/bma/lib/controllers/AbstractController.ts @@ -1,5 +1,6 @@ import {Server} from "../../../../../server"; import {dos2unix} from "../../../../lib/common-libs/dos2unix"; +import {CommonConstants} from "../../../../lib/common-libs/constants"; export abstract class AbstractController { @@ -36,6 +37,8 @@ export abstract class AbstractController { try { return await task(rawDocument) } catch (e) { + const event = CommonConstants.DocumentError + this.server.emit(event, e) this.logger.error(e); throw e; } diff --git a/app/modules/crawler/index.ts b/app/modules/crawler/index.ts index bb2b0b22c..b51e0a52d 100644 --- a/app/modules/crawler/index.ts +++ b/app/modules/crawler/index.ts @@ -12,15 +12,6 @@ import {Buid} from "../../lib/common-libs/buid" export const CrawlerDependency = { duniter: { - config: { - onLoading: async (conf:ConfDTO) => { - conf.swichOnTimeAheadBy = CrawlerConstants.SWITCH_ON_BRANCH_AHEAD_BY_X_MINUTES; - }, - beforeSave: async(conf:ConfDTO) => { - delete conf.swichOnTimeAheadBy - } - }, - service: { input: (server:Server, conf:ConfDTO, logger:any) => new Crawler(server, conf, logger) }, diff --git a/app/modules/crawler/lib/constants.ts b/app/modules/crawler/lib/constants.ts index 5d4ba9a45..23ca184d4 100644 --- a/app/modules/crawler/lib/constants.ts +++ b/app/modules/crawler/lib/constants.ts @@ -6,7 +6,6 @@ export const CrawlerConstants = { SYNC_LONG_TIMEOUT: 30 * 1000, // 30 seconds DEFAULT_TIMEOUT: 10 * 1000, // 10 seconds - SWITCH_ON_BRANCH_AHEAD_BY_X_MINUTES: 30, TRANSACTION_VERSION: CommonConstants.TRANSACTION_VERSION, FORK_ALLOWED: true, MAX_NUMBER_OF_PEERS_FOR_PULLING: 4, diff --git a/app/modules/crawler/lib/pulling.ts b/app/modules/crawler/lib/pulling.ts index 9e784215c..41472d518 100644 --- a/app/modules/crawler/lib/pulling.ts +++ b/app/modules/crawler/lib/pulling.ts @@ -198,13 +198,13 @@ export abstract class AbstractDAO extends PullingDao { } return result; }); - let avgGenTime = conf.avgGenTime; memberForks = _.filter(memberForks, (fork:any) => { - let blockDistance = (fork.current.number - localCurrent.number) * avgGenTime / 60; - let timeDistance = (fork.current.medianTime - localCurrent.medianTime) / 60; - logger && logger.debug('Fork of %s has blockDistance %s ; timeDistance %s ; required is >= %s for both values to try to follow the fork', fork.peer.pubkey.substr(0, 6), blockDistance.toFixed(2), timeDistance.toFixed(2), conf.swichOnTimeAheadBy); - return blockDistance >= conf.swichOnTimeAheadBy - && timeDistance >= conf.swichOnTimeAheadBy; + let blockDistanceInBlocks = (fork.current.number - localCurrent.number) + let timeDistanceInBlocks = (fork.current.medianTime - localCurrent.medianTime) / conf.avgGenTime + const requiredTimeAdvance = conf.switchOnHeadAdvance + logger && logger.debug('Fork of %s has blockDistance %s ; timeDistance %s ; required is >= %s for both values to try to follow the fork', fork.peer.pubkey.substr(0, 6), blockDistanceInBlocks.toFixed(2), timeDistanceInBlocks.toFixed(2), requiredTimeAdvance); + return blockDistanceInBlocks >= requiredTimeAdvance + && timeDistanceInBlocks >= requiredTimeAdvance }); // Remove any previous fork block await this.removeForks(); diff --git a/app/service/BlockchainService.ts b/app/service/BlockchainService.ts index 64badeae3..e2f0e3725 100644 --- a/app/service/BlockchainService.ts +++ b/app/service/BlockchainService.ts @@ -54,9 +54,9 @@ export class BlockchainService { return bb; } - checkBlock(block:any) { + checkBlock(block:any, withPoWAndSignature = true) { const dto = BlockDTO.fromJSONObject(block) - return this.mainContext.checkBlock(dto); + return this.mainContext.checkBlock(dto, withPoWAndSignature) } async branches() { @@ -144,36 +144,37 @@ export class BlockchainService { } else { return await this.mainContext.addBlock(dto) } - } else if (forkAllowed) { + } else { // add it as side chain - if (current.number - obj.number + 1 >= this.conf.forksize) { + if (parseInt(current.number) - parseInt(obj.number) + 1 >= this.conf.forksize) { throw 'Block out of fork window'; } let absolute = await this.dal.getAbsoluteBlockByNumberAndHash(obj.number, obj.hash) let res = null; if (!absolute) { res = await this.mainContext.addSideBlock(obj) + // we eventually try to swith **only if** we do not already have this blocK. Otherwise the block will be + // spread again to the network, which can end in an infinite ping-pong. + if (forkAllowed) { + await this.eventuallySwitchOnSideChain(current); + } + } else { + throw "Fork block already known" } - await this.tryToFork(current); return res; - } else { - throw "Fork block rejected by " + this.selfPubkey; } } - - tryToFork(current:DBBlock) { - return this.eventuallySwitchOnSideChain(current) - } - private async eventuallySwitchOnSideChain(current:DBBlock) { const branches = await this.branches() - const blocksAdvance = this.conf.swichOnTimeAheadBy / (this.conf.avgGenTime / 60); - const timeAdvance = this.conf.swichOnTimeAheadBy * 60; + const blocksAdvanceInBlocks = this.conf.switchOnHeadAdvance + const timeAdvance = this.conf.switchOnHeadAdvance * this.conf.avgGenTime let potentials = _.without(branches, current); - // We switch only to blockchain with X_MIN advance considering both theoretical time by block + written time - potentials = _.filter(potentials, (p:DBBlock) => p.number - current.number >= blocksAdvance - && p.medianTime - current.medianTime >= timeAdvance); + // We switch only to blockchain with X_BLOCKS in advance considering both theoretical time by block / avgGenTime, + written time / avgGenTime + potentials = _.filter(potentials, (p:DBBlock) => { + return p.number - current.number >= blocksAdvanceInBlocks + && p.medianTime - current.medianTime >= timeAdvance + }); this.logger.trace('SWITCH: %s branches...', branches.length); this.logger.trace('SWITCH: %s potential side chains...', potentials.length); for (const potential of potentials) { diff --git a/server.ts b/server.ts index 6866ec7bb..2bb568221 100644 --- a/server.ts +++ b/server.ts @@ -12,6 +12,7 @@ import {KeyGen, randomKey} from "./app/lib/common-libs/crypto/keyring"; import {parsers} from "./app/lib/common-libs/parsers/index"; import {Cloneable} from "./app/lib/dto/Cloneable"; import {DuniterDocument, duniterDocument2str} from "./app/lib/common-libs/constants"; +import {CrawlerConstants} from "./app/modules/crawler/lib/constants"; interface HookableServer { getMainEndpoint: (...args:any[]) => Promise<any> @@ -181,7 +182,7 @@ export class Server extends stream.Duplex implements HookableServer { } async writeBlock(obj:any) { - const res = await this.BlockchainService.submitBlock(obj, true, constants.NO_FORK_ALLOWED) + const res = await this.BlockchainService.submitBlock(obj, true, CrawlerConstants.FORK_ALLOWED) this.emitDocument(res, DuniterDocument.ENTITY_BLOCK) return res } diff --git a/test/fast/modules/crawler/block_pulling.ts b/test/fast/modules/crawler/block_pulling.ts index 709cf9f59..e7315850f 100644 --- a/test/fast/modules/crawler/block_pulling.ts +++ b/test/fast/modules/crawler/block_pulling.ts @@ -6,7 +6,7 @@ const should = require('should'); const _ = require('underscore'); let commonConf = { - swichOnTimeAheadBy: 30, + switchOnHeadAdvance: 1, avgGenTime: 30 * 60, forksize: 100 }; diff --git a/test/integration/branches2.js b/test/integration/branches2.js index ae32d6a6f..f68bbb304 100644 --- a/test/integration/branches2.js +++ b/test/integration/branches2.js @@ -31,7 +31,7 @@ const commonConf = { currency: 'bb', httpLogs: true, forksize: 10, - swichOnTimeAheadBy: 30, + switchOnHeadAdvance: 6, avgGenTime: 30 * 60, sigQty: 1 }; @@ -103,6 +103,8 @@ describe("SelfFork", function() { yield commitS2(); yield commitS2(); yield commitS2(); + yield commitS2(); + yield commitS2(); yield s1.writePeer(s2p); @@ -197,7 +199,7 @@ describe("SelfFork", function() { it('/current should exist', function() { return expectJSON(rp('http://127.0.0.1:7781/blockchain/current', { json: true }), { - number: 7 + number: 9 }); }); @@ -229,7 +231,7 @@ describe("SelfFork", function() { it('/current should exist', function() { return expectJSON(rp('http://127.0.0.1:7782/blockchain/current', { json: true }), { - number: 7 + number: 9 }); }); diff --git a/test/integration/branches_switch.js b/test/integration/branches_switch.js index 3c859e608..cab9d2df2 100644 --- a/test/integration/branches_switch.js +++ b/test/integration/branches_switch.js @@ -28,7 +28,7 @@ const s1 = duniter( '/bb11', MEMORY_MODE, _.extend({ - swichOnTimeAheadBy: 0, + switchOnHeadAdvance: 0, port: '7788', pair: { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', @@ -42,7 +42,7 @@ const s2 = duniter( '/bb12', MEMORY_MODE, _.extend({ - swichOnTimeAheadBy: 0, + switchOnHeadAdvance: 0, port: '7789', pair: { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', diff --git a/test/integration/register-fork-blocks.js b/test/integration/register-fork-blocks.js new file mode 100644 index 000000000..6a1183e83 --- /dev/null +++ b/test/integration/register-fork-blocks.js @@ -0,0 +1,209 @@ +"use strict"; + +const _ = require('underscore'); +const co = require('co'); +const assert = require('assert'); +const user = require('./tools/user'); +const commit = require('./tools/commit'); +const toolbox = require('./tools/toolbox'); +const CommonConstants = require('../../app/lib/common-libs/constants').CommonConstants + +const now = 1500000000 +const forksize = 10 + +const s1 = toolbox.server({ + + // The common conf + medianTimeBlocks: 1, + avgGenTime: 11, + udTime0: now, + udReevalTime0: now, + forksize, + + pair: { + pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', + sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP' + } +}); + +const s2 = toolbox.server({ + + // Particular conf + switchOnHeadAdvance: 5, + forksize, + + pair: { + pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', + sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE' + } +}); + +const s3 = toolbox.server({ + + // Particular conf + switchOnHeadAdvance: 5, + forksize, + + pair: { + pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', + sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F' + } +}); + +const cat1 = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 }); +const tac1 = user('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 }); +const toc1 = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 }); + +describe("Fork blocks", function() { + + before(() => co(function*() { + + yield s1.prepareForNetwork(); + yield s2.prepareForNetwork(); + yield s3.prepareForNetwork(); + + // Publishing identities + yield cat1.createIdentity(); + yield tac1.createIdentity(); + yield toc1.createIdentity(); + yield cat1.cert(tac1); + yield tac1.cert(cat1); + yield tac1.cert(toc1); + yield cat1.join(); + yield tac1.join(); + yield toc1.join(); + })); + + after(() => { + return Promise.all([ + s1.closeCluster(), + s2.closeCluster(), + s3.closeCluster() + ]) + }) + + it('should create a common blockchain', () => co(function*() { + const b0 = yield s1.commit({ time: now }) + const b1 = yield s1.commit({ time: now + 11 }) + const b2 = yield s1.commit({ time: now + 22 }) + yield s2.writeBlock(b0) + yield s2.writeBlock(b1) + yield s2.writeBlock(b2) + yield s3.writeBlock(b0) + yield s3.writeBlock(b1) + yield s3.writeBlock(b2) + })) + + it('should exist the same block on each node', () => co(function*() { + yield s1.expectJSON('/blockchain/current', { + number: 2 + }) + yield s2.expectJSON('/blockchain/current', { + number: 2 + }) + })) + + it('should be able to fork, and notify each node', () => co(function*() { + const b3a = yield s1.commit({ time: now + 33 }) + const b3b = yield s2.commit({ time: now + 33 }) + yield s1.writeBlock(b3b) + yield s2.writeBlock(b3a) + })) + + it('should exist a different third block on each node', () => co(function*() { + yield s1.expectJSON('/blockchain/current', { + number: 3, + hash: "74AB356F0E6CD9AA6F752E58FFCD65D5F8C95CDAA93576A40457CC3598C4E3D1" + }) + yield s2.expectJSON('/blockchain/current', { + number: 3, + hash: "2C3555F4009461C81F7209EAAD7DA831D8451708D06BB1173CCB40746CD0641B" + }) + })) + + it('should exist both branches on each node', () => co(function*() { + yield s1.expect('/blockchain/branches', (res) => { + assert.equal(res.blocks.length, 2) + assert.equal(res.blocks[0].number, 3) + assert.equal(res.blocks[0].hash, '2C3555F4009461C81F7209EAAD7DA831D8451708D06BB1173CCB40746CD0641B') + assert.equal(res.blocks[1].number, 3) + assert.equal(res.blocks[1].hash, '74AB356F0E6CD9AA6F752E58FFCD65D5F8C95CDAA93576A40457CC3598C4E3D1') + }) + yield s2.expect('/blockchain/branches', (res) => { + assert.equal(res.blocks.length, 2) + assert.equal(res.blocks[0].number, 3) + assert.equal(res.blocks[0].hash, '74AB356F0E6CD9AA6F752E58FFCD65D5F8C95CDAA93576A40457CC3598C4E3D1') + assert.equal(res.blocks[1].number, 3) + assert.equal(res.blocks[1].hash, '2C3555F4009461C81F7209EAAD7DA831D8451708D06BB1173CCB40746CD0641B') + }) + })) + + let b4a, b5a, b6a, b7a, b8a + + it('should be able to grow S1\'s blockchain', () => co(function*() { + b4a = yield s1.commit({time: now + 44}) + b5a = yield s1.commit({time: now + 55}) + b6a = yield s1.commit({time: now + 66}) + b7a = yield s1.commit({time: now + 77}) + b8a = yield s1.commit({time: now + 88}) + })) + + it('should refuse known fork blocks', () => co(function*() { + yield s1.sharePeeringWith(s2) + yield s2.sharePeeringWith(s1) + yield s2.writeBlock(b4a) + const b3c = yield s3.commit({ time: now + 33 }) + yield new Promise((res, rej) => { + const event = CommonConstants.DocumentError + s2.on(event, (e) => { + try { + assert.equal(e, 'Fork block already known') + res() + } catch (e) { + rej(e) + } + }) + // Trigger the third-party fork block writing + s2.writeBlock(b3c) + }) + })) + + it('should be able to make one fork grow enough to make one node switch', () => co(function*() { + yield s2.writeBlock(b5a) + yield s2.writeBlock(b6a) + yield s2.writeBlock(b7a) + yield s2.writeBlock(b8a) + })) + + it('should exist a same current block on each node', () => co(function*() { + yield s1.expectJSON('/blockchain/current', { + number: 8, + hash: "B8D2AA2A5556F7A2837FB4B881FCF50595F855D0BF8F71C0B432E27216BBA40B" + }) + yield s2.expectJSON('/blockchain/current', { + number: 8, + hash: "B8D2AA2A5556F7A2837FB4B881FCF50595F855D0BF8F71C0B432E27216BBA40B" + }) + })) + + it('should exist 2 branches on each node', () => co(function*() { + yield s1.expect('/blockchain/branches', (res) => { + assert.equal(res.blocks.length, 3) + assert.equal(res.blocks[0].number, 3) + assert.equal(res.blocks[0].hash, '2C3555F4009461C81F7209EAAD7DA831D8451708D06BB1173CCB40746CD0641B') // This is s2 fork! + assert.equal(res.blocks[1].number, 3) + assert.equal(res.blocks[1].hash, '9A0FA1F0899124444ADC5B2C0AB66AC5B4303A0D851BED2E7382BB57E10AA2C5') + assert.equal(res.blocks[2].number, 8) + assert.equal(res.blocks[2].hash, 'B8D2AA2A5556F7A2837FB4B881FCF50595F855D0BF8F71C0B432E27216BBA40B') + }) + yield s2.expect('/blockchain/branches', (res) => { + assert.equal(res.blocks.length, 3) + assert.equal(res.blocks[0].number, 3) + assert.equal(res.blocks[0].hash, '2C3555F4009461C81F7209EAAD7DA831D8451708D06BB1173CCB40746CD0641B') // This is s2 fork! + assert.equal(res.blocks[1].number, 3) + assert.equal(res.blocks[1].hash, '9A0FA1F0899124444ADC5B2C0AB66AC5B4303A0D851BED2E7382BB57E10AA2C5') + assert.equal(res.blocks[2].number, 8) + assert.equal(res.blocks[2].hash, 'B8D2AA2A5556F7A2837FB4B881FCF50595F855D0BF8F71C0B432E27216BBA40B') + }) + })) +}); diff --git a/test/integration/tools/toolbox.ts b/test/integration/tools/toolbox.ts index 1faa3b0bf..53b77b11d 100644 --- a/test/integration/tools/toolbox.ts +++ b/test/integration/tools/toolbox.ts @@ -194,7 +194,7 @@ export const NewTestingServer = (conf:any) => { remoteipv4: HOST, currency: conf.currency || CURRENCY_NAME, httpLogs: true, - forksize: 3 + forksize: conf.forksize || 3 }; if (conf.sigQty === undefined) { conf.sigQty = 1; -- GitLab