Commit 2bc114cd authored by Cédric Moreau's avatar Cédric Moreau
Browse files

[enh] Protocol: allow document v11 upgrade

parent 642f3300
......@@ -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,
......
......@@ -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
})()
}
}
......@@ -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) {
......
......@@ -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
}
}
......@@ -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)
}
......
......@@ -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),
......
......@@ -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
......
......@@ -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);
......
......@@ -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')
})
})
})
......@@ -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) => {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment