From 2bc114cdb5809135ee7a89c4f873018645ed502e Mon Sep 17 00:00:00 2001 From: cgeek <cem.moreau@gmail.com> Date: Tue, 20 Nov 2018 16:19:38 +0100 Subject: [PATCH] [enh] Protocol: allow document v11 upgrade --- app/lib/common-libs/constants.ts | 3 +- app/lib/rules/local_rules.ts | 26 ++++++++++++---- app/modules/prover/lib/blockGenerator.ts | 6 ++-- app/modules/prover/lib/blockProver.ts | 30 +++++++++++++++++-- app/modules/prover/lib/engine.ts | 5 ++-- app/modules/prover/lib/powCluster.ts | 8 +++-- doc/Protocol.md | 2 +- test/integration/branches/branches_revert2.ts | 6 ++-- .../fork-resolution/register-fork-blocks.ts | 28 ++++++++--------- test/integration/membership_chainability.ts | 4 +++ 10 files changed, 84 insertions(+), 34 deletions(-) diff --git a/app/lib/common-libs/constants.ts b/app/lib/common-libs/constants.ts index bfe7264cc..5c44b5046 100755 --- a/app/lib/common-libs/constants.ts +++ b/app/lib/common-libs/constants.ts @@ -20,7 +20,7 @@ const SIGNATURE = "[A-Za-z0-9+\\/=]{87,88}" const USER_ID = "[A-Za-z0-9_-]{2,100}" const INTEGER = "(0|[1-9]\\d{0,18})" const FINGERPRINT = "[A-F0-9]{64}" -const BLOCK_VERSION = "(10)" +const BLOCK_VERSION = "(10|11)" const TX_VERSION = "(10)" const DIVIDEND = "[1-9][0-9]{0,5}" const ZERO_OR_POSITIVE_INT = "0|[1-9][0-9]{0,18}" @@ -106,6 +106,7 @@ export const CommonConstants = { }, BLOCK_GENERATED_VERSION: 10, + BLOCK_NEW_GENERATED_VERSION: 11, LAST_VERSION_FOR_TX: 10, TRANSACTION_VERSION: 10, DOCUMENTS_VERSION: 10, diff --git a/app/lib/rules/local_rules.ts b/app/lib/rules/local_rules.ts index c1f26fb4d..15569c419 100644 --- a/app/lib/rules/local_rules.ts +++ b/app/lib/rules/local_rules.ts @@ -22,6 +22,7 @@ import {CommonConstants} from "../common-libs/constants" import {IdentityDTO} from "../dto/IdentityDTO" import {MembershipDTO} from "../dto/MembershipDTO" import {Underscore} from "../common-libs/underscore" +import {FileDAL} from "../dal/fileDAL" const constants = CommonConstants const maxAcceleration = require('./helpers').maxAcceleration @@ -522,13 +523,28 @@ export const LOCAL_RULES_HELPERS = { } }, - getMaxPossibleVersionNumber: async (current:DBBlock|null) => { + getMaxPossibleVersionNumber: async (current:DBBlock|null, dal: FileDAL) => { // Looking at current blockchain, find what is the next maximum version we can produce - // 1. We follow previous block's version - let version = current ? current.version : constants.BLOCK_GENERATED_VERSION; + return !current - // 2. If we can, we go to the next version - return version; + // 1. We use legacy version + ? constants.BLOCK_GENERATED_VERSION : (async () => { + + // 2. If we can, we go to the next version + const blocksInFrame = (await dal.getBlocksBetween(current.number - current.issuersFrame + 1, current.number)) + .sort((b1, b2) => b1.number - b2.number) + const uniqIssuersInFrame = Underscore.uniq(blocksInFrame.map(b => b.issuer)) + const lastNonceOfEachIssuer = uniqIssuersInFrame.map(issuer => String(blocksInFrame.filter(b => b.issuer === issuer)[0].nonce)) + const nbNoncesWithNextVersionCode = lastNonceOfEachIssuer.filter(nonce => nonce.substr(-11, 3) === '999').length + + // More than 70% of the computing network converted? Let's go to next version. + if (Math.floor(nbNoncesWithNextVersionCode / uniqIssuersInFrame.length) > 0.7) { + return constants.BLOCK_NEW_GENERATED_VERSION + } + + // Otherwise, we stay on same version + return current.version + })() } } diff --git a/app/modules/prover/lib/blockGenerator.ts b/app/modules/prover/lib/blockGenerator.ts index 1f30d044e..dc592a581 100644 --- a/app/modules/prover/lib/blockGenerator.ts +++ b/app/modules/prover/lib/blockGenerator.ts @@ -104,6 +104,7 @@ export class BlockGenerator { vHEAD_1.medianTime = simulationValues.medianTime } const current = await this.dal.getCurrentBlockOrNull(); + const blockVersion = (manualValues && manualValues.version) || (await LOCAL_RULES_HELPERS.getMaxPossibleVersionNumber(current, this.dal)) const revocations = await this.dal.getRevocatingMembers(); const exclusions = await this.dal.getToBeKickedPubkeys(); const wereExcludeds = await this.dal.getRevokedPubkeys(); @@ -126,7 +127,7 @@ export class BlockGenerator { }); }); // Create the block - return this.createBlock(current, newcomers, leavers, newCertsFromWoT, revocations, exclusions, wereExcludeds, transactions, manualValues); + return this.createBlock(blockVersion, current, newcomers, leavers, newCertsFromWoT, revocations, exclusions, wereExcludeds, transactions, manualValues); } private async findTransactions(current:DBBlock|null, options:{ dontCareAboutChaining?:boolean }) { @@ -450,6 +451,7 @@ export class BlockGenerator { } private async createBlock( + blockVersion: number, current:DBBlock|null, joinData:{ [pub:string]: PreJoin }, leaveData:{ [pub:string]: LeaveData }, @@ -501,7 +503,7 @@ export class BlockGenerator { block.medianTime = vHEAD.medianTime; } // Choose the version - block.version = (manualValues && manualValues.version) || (await LOCAL_RULES_HELPERS.getMaxPossibleVersionNumber(current)); + block.version = blockVersion block.currency = current ? current.currency : this.conf.currency; block.nonce = 0; if (!this.conf.dtReeval) { diff --git a/app/modules/prover/lib/blockProver.ts b/app/modules/prover/lib/blockProver.ts index 3d1489aca..9bcdfe749 100644 --- a/app/modules/prover/lib/blockProver.ts +++ b/app/modules/prover/lib/blockProver.ts @@ -93,7 +93,7 @@ export class WorkerFarm { * Starts a new computation of PoW * @param stuff The necessary data for computing the PoW */ - async askNewProof(stuff:any) { + async askNewProof(stuff: ProofAsk) { // Starts the PoW this.powPromise = querablep(this.theEngine.prove(stuff)) const res = await this.powPromise @@ -163,6 +163,7 @@ export class BlockProver { const remainder = difficulty % 16; const nbZeros = (difficulty - remainder) / 16; const highMark = CommonConstants.PROOF_OF_WORK.UPPER_BOUND[remainder]; + const notifyVersionJumpReady = block.version === 10 && CommonConstants.BLOCK_NEW_GENERATED_VERSION === 11 return (async () => { @@ -189,7 +190,7 @@ export class BlockProver { conf: { powNoSecurity: this.conf.powNoSecurity, cpu: this.conf.cpu, - prefix: this.conf.prefix, + prefix: this.conf.prefix ? String(this.conf.prefix) : '', avgGenTime: this.conf.avgGenTime, medianTimeBlocks: this.conf.medianTimeBlocks }, @@ -198,7 +199,8 @@ export class BlockProver { highMark: highMark, forcedTime: forcedTime, pair: this.pair - } + }, + specialNonce: notifyVersionJumpReady ? 999 * (ProverConstants.NONCE_RANGE / 1000) : 0, }); if (!result) { this.logger.info('GIVEN proof-of-work for block#%s with %s leading zeros followed by [0-' + highMark + ']! stop PoW for %s', block.number, nbZeros, this.pair && this.pair.pub.slice(0,6)); @@ -231,3 +233,25 @@ export class BlockProver { this.server && this.server.push({ pow: { found, hash } }); } } + +export interface ProofAsk { + initialTestsPerRound?: number + maxDuration?: number + specialNonce?: number + newPoW: { + conf: { + powNoSecurity?: boolean + cpu?: number + prefix?: string + nbCores?: number + avgGenTime: number + medianTimeBlocks: number + }, + block: any, + zeros: number + highMark: string + forcedTime?: number + pair: Keypair|null + turnDuration?: number + } +} diff --git a/app/modules/prover/lib/engine.ts b/app/modules/prover/lib/engine.ts index df8991dab..54b0b4c17 100644 --- a/app/modules/prover/lib/engine.ts +++ b/app/modules/prover/lib/engine.ts @@ -13,7 +13,8 @@ import {Master as PowCluster} from "./powCluster" import {ConfDTO} from "../../../lib/dto/ConfDTO" -import {FileDAL} from "../../../lib/dal/fileDAL"; +import {FileDAL} from "../../../lib/dal/fileDAL" +import {ProofAsk} from "./blockProver" const os = require('os') @@ -46,7 +47,7 @@ export class PowEngine { return this.cluster.initCluster() } - async prove(stuff:any) { + async prove(stuff: ProofAsk) { await this.cluster.cancelWork() return await this.cluster.proveByWorkers(stuff) } diff --git a/app/modules/prover/lib/powCluster.ts b/app/modules/prover/lib/powCluster.ts index 3ee90d488..359a82533 100644 --- a/app/modules/prover/lib/powCluster.ts +++ b/app/modules/prover/lib/powCluster.ts @@ -15,8 +15,9 @@ import {ConfDTO} from "../../../lib/dto/ConfDTO" import {ProverConstants} from "./constants" import {createPowWorker} from "./proof" import {PowWorker} from "./PowWorker" -import {FileDAL} from "../../../lib/dal/fileDAL"; +import {FileDAL} from "../../../lib/dal/fileDAL" import {Underscore} from "../../../lib/common-libs/underscore" +import {ProofAsk} from "./blockProver" const nuuid = require('node-uuid'); const cluster = require('cluster') @@ -171,7 +172,7 @@ export class Master { this.slaves = [] } - async proveByWorkers(stuff:any) { + async proveByWorkers(stuff: ProofAsk) { // Eventually spawn the workers if (this.slaves.length === 0) { @@ -194,6 +195,7 @@ export class Master { // Start the salves' job const asks = this.slaves.map(async (s, index) => { + const nonceBeginning = stuff.specialNonce || s.nonceBeginning const proof = await s.worker.askProof({ uuid, command: 'newPoW', @@ -202,7 +204,7 @@ export class Master { initialTestsPerRound: stuff.initialTestsPerRound, maxDuration: stuff.maxDuration, block: stuff.newPoW.block, - nonceBeginning: s.nonceBeginning, + nonceBeginning, zeros: stuff.newPoW.zeros, highMark: stuff.newPoW.highMark, pair: Underscore.clone(stuff.newPoW.pair), diff --git a/doc/Protocol.md b/doc/Protocol.md index 2a4649f9e..ba7ac24c8 100644 --- a/doc/Protocol.md +++ b/doc/Protocol.md @@ -1177,7 +1177,7 @@ Local validation verifies the coherence of a well-formatted block, without any o Rule: - HEAD.version == 10 + HEAD.version == 10 || HEAD.version == 11 ##### InnerHash diff --git a/test/integration/branches/branches_revert2.ts b/test/integration/branches/branches_revert2.ts index 8b7ce66fe..6ac9b3778 100644 --- a/test/integration/branches/branches_revert2.ts +++ b/test/integration/branches/branches_revert2.ts @@ -117,7 +117,7 @@ describe("Revert two blocks", function() { 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('identifier').equal('5F91D05DD1B1C9CAFDBCF5538C63DAF770A20790D08C9A88E0625A8D5599825D'); 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); @@ -257,7 +257,7 @@ describe("Revert two blocks", function() { return expectAnswer(rp('http://127.0.0.1:7712/tx/sources/HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd'), (body:string) => { 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('identifier').equal('EE74E456FC16888FF24C3A9749B9E3A8D5005A9CCE988B2CFF4619AFEA50F890'); 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); @@ -272,7 +272,7 @@ describe("Revert two blocks", function() { 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('identifier').equal('EE74E456FC16888FF24C3A9749B9E3A8D5005A9CCE988B2CFF4619AFEA50F890'); 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); diff --git a/test/integration/fork-resolution/register-fork-blocks.ts b/test/integration/fork-resolution/register-fork-blocks.ts index d976ad2cc..0fbe8deac 100644 --- a/test/integration/fork-resolution/register-fork-blocks.ts +++ b/test/integration/fork-resolution/register-fork-blocks.ts @@ -133,11 +133,11 @@ describe("Fork blocks", function() { it('should exist a different third block on each node', async () => { await s1.expectJSON('/blockchain/current', { number: 3, - hash: "74AB356F0E6CD9AA6F752E58FFCD65D5F8C95CDAA93576A40457CC3598C4E3D1" + hash: "2C0451EA29CA759AE8296D0751989067AEEC35050BC8CD5623B05C0665C24471" }) await s2.expectJSON('/blockchain/current', { number: 3, - hash: "2C3555F4009461C81F7209EAAD7DA831D8451708D06BB1173CCB40746CD0641B" + hash: "33038E3E9C1BFB8328234CDD42D1F47B8D362A78161B03E43732CA7432D10A76" }) }) @@ -145,16 +145,16 @@ describe("Fork blocks", function() { await s1.expect('/blockchain/branches', (res:HttpBranches) => { assert.equal(res.blocks.length, 2) assert.equal(res.blocks[0].number, 3) - assert.equal(res.blocks[0].hash, '2C3555F4009461C81F7209EAAD7DA831D8451708D06BB1173CCB40746CD0641B') + assert.equal(res.blocks[0].hash, '33038E3E9C1BFB8328234CDD42D1F47B8D362A78161B03E43732CA7432D10A76') assert.equal(res.blocks[1].number, 3) - assert.equal(res.blocks[1].hash, '74AB356F0E6CD9AA6F752E58FFCD65D5F8C95CDAA93576A40457CC3598C4E3D1') + assert.equal(res.blocks[1].hash, '2C0451EA29CA759AE8296D0751989067AEEC35050BC8CD5623B05C0665C24471') }) await s2.expect('/blockchain/branches', (res:HttpBranches) => { assert.equal(res.blocks.length, 2) assert.equal(res.blocks[0].number, 3) - assert.equal(res.blocks[0].hash, '74AB356F0E6CD9AA6F752E58FFCD65D5F8C95CDAA93576A40457CC3598C4E3D1') + assert.equal(res.blocks[0].hash, '2C0451EA29CA759AE8296D0751989067AEEC35050BC8CD5623B05C0665C24471') assert.equal(res.blocks[1].number, 3) - assert.equal(res.blocks[1].hash, '2C3555F4009461C81F7209EAAD7DA831D8451708D06BB1173CCB40746CD0641B') + assert.equal(res.blocks[1].hash, '33038E3E9C1BFB8328234CDD42D1F47B8D362A78161B03E43732CA7432D10A76') }) }) @@ -203,11 +203,11 @@ describe("Fork blocks", function() { it('should exist a same current block on each node', async () => { await s1.expectJSON('/blockchain/current', { number: 8, - hash: "B8D2AA2A5556F7A2837FB4B881FCF50595F855D0BF8F71C0B432E27216BBA40B" + hash: "C41F10519A24950C051F3ABBBF71775D9EF836374EF538897DFFF08E7A3F5E50" }) await s2.expectJSON('/blockchain/current', { number: 8, - hash: "B8D2AA2A5556F7A2837FB4B881FCF50595F855D0BF8F71C0B432E27216BBA40B" + hash: "C41F10519A24950C051F3ABBBF71775D9EF836374EF538897DFFF08E7A3F5E50" }) }) @@ -215,20 +215,20 @@ describe("Fork blocks", function() { await s1.expect('/blockchain/branches', (res:HttpBranches) => { 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[0].hash, '33038E3E9C1BFB8328234CDD42D1F47B8D362A78161B03E43732CA7432D10A76') // This is s2 fork! assert.equal(res.blocks[1].number, 3) - assert.equal(res.blocks[1].hash, '9A0FA1F0899124444ADC5B2C0AB66AC5B4303A0D851BED2E7382BB57E10AA2C5') + assert.equal(res.blocks[1].hash, '7A1982E7746DE1993F8900C2D453A1E7C010B2BDF304DB83BCBF84932CE8A630') assert.equal(res.blocks[2].number, 8) - assert.equal(res.blocks[2].hash, 'B8D2AA2A5556F7A2837FB4B881FCF50595F855D0BF8F71C0B432E27216BBA40B') + assert.equal(res.blocks[2].hash, 'C41F10519A24950C051F3ABBBF71775D9EF836374EF538897DFFF08E7A3F5E50') }) await s2.expect('/blockchain/branches', (res:HttpBranches) => { 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[0].hash, '33038E3E9C1BFB8328234CDD42D1F47B8D362A78161B03E43732CA7432D10A76') // This is s2 fork! assert.equal(res.blocks[1].number, 3) - assert.equal(res.blocks[1].hash, '9A0FA1F0899124444ADC5B2C0AB66AC5B4303A0D851BED2E7382BB57E10AA2C5') + assert.equal(res.blocks[1].hash, '7A1982E7746DE1993F8900C2D453A1E7C010B2BDF304DB83BCBF84932CE8A630') assert.equal(res.blocks[2].number, 8) - assert.equal(res.blocks[2].hash, 'B8D2AA2A5556F7A2837FB4B881FCF50595F855D0BF8F71C0B432E27216BBA40B') + assert.equal(res.blocks[2].hash, 'C41F10519A24950C051F3ABBBF71775D9EF836374EF538897DFFF08E7A3F5E50') }) }) }) diff --git a/test/integration/membership_chainability.ts b/test/integration/membership_chainability.ts index 95ffc5f94..d0e571a16 100644 --- a/test/integration/membership_chainability.ts +++ b/test/integration/membership_chainability.ts @@ -12,6 +12,7 @@ // GNU Affero General Public License for more details. import {simpleNodeWith2Users} from "./tools/toolbox" +import {CommonConstants} from "../../app/lib/common-libs/constants" describe("Membership chainability", function() { @@ -34,11 +35,14 @@ describe("Membership chainability", function() { const res1 = await simpleNodeWith2Users(conf) s1 = res1.s1 cat = res1.cat + const nowVersion = CommonConstants.BLOCK_NEW_GENERATED_VERSION + CommonConstants.BLOCK_NEW_GENERATED_VERSION = 10 await s1.commit({ time: now }) await s1.commit({ time: now }) await s1.commit({ time: now, actives: [ 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd:rppB5NEwmdMUCxw3N/QPMk+V1h2Jpn0yxTzdO2xxcNN3MACv6x8vNTChWwM6DOq+kXiQHTczFzoux+82WkMfDQ==:1-12D7B9BEBE941F6929A4A61CDC06DEEEFCB00FD1DA72E42FFF7B19A338D421E1:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:cat' ]}) + CommonConstants.BLOCK_NEW_GENERATED_VERSION = nowVersion }) it('current should be the 2nd', () => s1.expect('/blockchain/current', (res:any) => { -- GitLab