diff --git a/app/cli.ts b/app/cli.ts index 3c2e495153853106e8b04d3253c36be1703752c1..6a6d3924b91387ab71fc3c49700c429352d3277c 100644 --- a/app/cli.ts +++ b/app/cli.ts @@ -41,6 +41,7 @@ export const ExecuteCommand = () => { .option('--addep <endpoint>', 'With `config` command, add given endpoint to the list of endpoints of this node') .option('--remep <endpoint>', 'With `config` command, remove given endpoint to the list of endpoints of this node') + .option('--no-eco-mode', 'Do not reduce CPU usage for proof-of-work computation') .option('--cpu <percent>', 'Percent of CPU usage for proof-of-work computation', parsePercent) .option('--nb-cores <number>', 'Number of cores uses for proof-of-work computation', parseInt) .option('--prefix <nodeId>', 'Prefix node id for the first character of nonce', parseInt) diff --git a/app/lib/dto/ConfDTO.ts b/app/lib/dto/ConfDTO.ts index 2e77e92fc70336c82b99bbb7b908ee9251918d09..b6ff36a94ed90531156ecdc7b6beb4023491c7fd 100644 --- a/app/lib/dto/ConfDTO.ts +++ b/app/lib/dto/ConfDTO.ts @@ -91,6 +91,7 @@ export class ConfDTO implements CurrencyConfDTO, KeypairConfDTO, NetworkConfDTO, public rmEndpoints: string[], public rootoffset: number, public upInterval: number, + public ecoMode: boolean|true, public cpu: number, public nbCores: number, public prefix: number, @@ -162,7 +163,7 @@ export class ConfDTO implements CurrencyConfDTO, KeypairConfDTO, NetworkConfDTO, ) {} static mock() { - return new ConfDTO("", "", [], [], 0, 3600 * 1000, constants.PROOF_OF_WORK.DEFAULT.CPU, 1, constants.PROOF_OF_WORK.DEFAULT.PREFIX, 0, 0, constants.CONTRACT.DEFAULT.C, constants.CONTRACT.DEFAULT.DT, constants.CONTRACT.DEFAULT.DT_REEVAL, 0, constants.CONTRACT.DEFAULT.UD0, 0, 0, constants.CONTRACT.DEFAULT.STEPMAX, constants.CONTRACT.DEFAULT.SIGPERIOD, 0, constants.CONTRACT.DEFAULT.SIGVALIDITY, constants.CONTRACT.DEFAULT.MSVALIDITY, constants.CONTRACT.DEFAULT.SIGQTY, constants.CONTRACT.DEFAULT.SIGSTOCK, constants.CONTRACT.DEFAULT.X_PERCENT, constants.CONTRACT.DEFAULT.PERCENTROT, constants.CONTRACT.DEFAULT.POWDELAY, constants.CONTRACT.DEFAULT.AVGGENTIME, constants.CONTRACT.DEFAULT.MEDIANTIMEBLOCKS, false, 3000, false, constants.BRANCHES.DEFAULT_WINDOW_SIZE, constants.CONTRACT.DEFAULT.IDTYWINDOW, constants.CONTRACT.DEFAULT.MSWINDOW, constants.CONTRACT.DEFAULT.SIGWINDOW, 0, { pub:'', sec:'' }, null, "", "", 0, "", "", "", "", 0, "", "", null, false, "", true, true, false, new ProxiesConf(), undefined) + return new ConfDTO("", "", [], [], 0, 3600 * 1000, true, constants.PROOF_OF_WORK.DEFAULT.CPU, 1, constants.PROOF_OF_WORK.DEFAULT.PREFIX, 0, 0, constants.CONTRACT.DEFAULT.C, constants.CONTRACT.DEFAULT.DT, constants.CONTRACT.DEFAULT.DT_REEVAL, 0, constants.CONTRACT.DEFAULT.UD0, 0, 0, constants.CONTRACT.DEFAULT.STEPMAX, constants.CONTRACT.DEFAULT.SIGPERIOD, 0, constants.CONTRACT.DEFAULT.SIGVALIDITY, constants.CONTRACT.DEFAULT.MSVALIDITY, constants.CONTRACT.DEFAULT.SIGQTY, constants.CONTRACT.DEFAULT.SIGSTOCK, constants.CONTRACT.DEFAULT.X_PERCENT, constants.CONTRACT.DEFAULT.PERCENTROT, constants.CONTRACT.DEFAULT.POWDELAY, constants.CONTRACT.DEFAULT.AVGGENTIME, constants.CONTRACT.DEFAULT.MEDIANTIMEBLOCKS, false, 3000, false, constants.BRANCHES.DEFAULT_WINDOW_SIZE, constants.CONTRACT.DEFAULT.IDTYWINDOW, constants.CONTRACT.DEFAULT.MSWINDOW, constants.CONTRACT.DEFAULT.SIGWINDOW, 0, { pub:'', sec:'' }, null, "", "", 0, "", "", "", "", 0, "", "", null, false, "", true, true, false, new ProxiesConf(), undefined) } static defaultConf() { diff --git a/app/modules/prover/lib/blockProver.ts b/app/modules/prover/lib/blockProver.ts index 9cd215d98d478a456857b52f9f5c5388e1afa153..1b6d051c2f284f3040a95bf6606548837c2d022a 100644 --- a/app/modules/prover/lib/blockProver.ts +++ b/app/modules/prover/lib/blockProver.ts @@ -177,6 +177,7 @@ export class BlockProver { newPoW: { turnDuration: os.arch().match(/arm/) ? CommonConstants.POW_TURN_DURATION_ARM : CommonConstants.POW_TURN_DURATION_PC, conf: { + nbCores: this.conf.nbCores, cpu: this.conf.cpu, prefix: this.conf.prefix, avgGenTime: this.conf.avgGenTime, @@ -196,16 +197,28 @@ export class BlockProver { const proof = result.block; const testsCount = result.testsCount; const duration = (Date.now() - start); - const testsPerSecond = (testsCount / (duration / 1000)).toFixed(2); - this.logger.info('Done: #%s, %s in %ss (%s tests, ~%s tests/s)', block.number, proof.hash, (duration / 1000).toFixed(2), testsCount, testsPerSecond); + const testsPerSecond = (testsCount / (duration / 1000)); + this.logger.info('Done: #%s, %s in %ss instead of %ss (%s tests, ~%s tests/s)', block.number, proof.hash, (duration / 1000).toFixed(2), + this.conf.avgGenTime, testsCount, testsPerSecond.toFixed(2)); this.logger.info('FOUND proof-of-work with %s leading zeros followed by [0-' + highMark + ']!', nbZeros); + if(this.conf.ecoMode && this.conf.nbCores*testsPerSecond > 300) { + if(this.conf.nbCores > 1) { + this.logger.info("Reducing number of CPU cores "+this.conf.nbCores) + this.conf.nbCores = this.conf.nbCores -1 + } + else if(this.conf.cpu > 0.19){ + let cpu:number = this.conf.cpu - 0.1 + this.logger.info("Slowing down the CPU to "+cpu) + this.changeCPU(cpu) + } + } return BlockDTO.fromJSONObject(proof) } })() }; async changeCPU(cpu:number) { - this.conf.cpu = cpu; + this.conf.cpu = Math.max(0.01, Math.min(1.0, cpu)); const farm = await this.getWorker() return farm.changeCPU(cpu) } diff --git a/app/modules/prover/lib/powCluster.ts b/app/modules/prover/lib/powCluster.ts index 4d4820777cb9b279aebea2d09680d1be0b3aab1f..8e6e658434c893ddc695bc50bb07f15078c92f91 100644 --- a/app/modules/prover/lib/powCluster.ts +++ b/app/modules/prover/lib/powCluster.ts @@ -185,25 +185,27 @@ export class Master { // Start the salves' job this.slaves.forEach((s:any, index) => { - s.worker.send({ - uuid, - command: 'newPoW', - value: { - block: stuff.newPoW.block, - nonceBeginning: s.nonceBeginning, - zeros: stuff.newPoW.zeros, - highMark: stuff.newPoW.highMark, - pair: _.clone(stuff.newPoW.pair), - forcedTime: stuff.newPoW.forcedTime, - turnDuration: stuff.newPoW.turnDuration, - conf: { - medianTimeBlocks: stuff.newPoW.conf.medianTimeBlocks, - avgGenTime: stuff.newPoW.conf.avgGenTime, - cpu: stuff.newPoW.conf.cpu, - prefix: stuff.newPoW.conf.prefix + if(index < stuff.newPoW.conf.nbCores) { + s.worker.send({ + uuid, + command: 'newPoW', + value: { + block: stuff.newPoW.block, + nonceBeginning: s.nonceBeginning, + zeros: stuff.newPoW.zeros, + highMark: stuff.newPoW.highMark, + pair: _.clone(stuff.newPoW.pair), + forcedTime: stuff.newPoW.forcedTime, + turnDuration: stuff.newPoW.turnDuration, + conf: { + medianTimeBlocks: stuff.newPoW.conf.medianTimeBlocks, + avgGenTime: stuff.newPoW.conf.avgGenTime, + cpu: stuff.newPoW.conf.cpu, + prefix: stuff.newPoW.conf.prefix + } } - } - }) + }) + } }) return await this.currentPromise diff --git a/index.ts b/index.ts index ecf7be9d67231df6e4e63ef96c903457272b675d..daf1b333be0293972a011a2c4e59ff9eaf949bd2 100644 --- a/index.ts +++ b/index.ts @@ -443,6 +443,7 @@ function commandLineConf(program:any, conf:any = {}) { conf = conf || {}; const cli = { currency: program.currency, + ecoMode: program.ecoMode, cpu: program.cpu, nbCores: program.nbCores, prefix: program.prefix, @@ -485,6 +486,7 @@ function commandLineConf(program:any, conf:any = {}) { // Update the rest of the conf if (cli.currency) conf.currency = cli.currency; if (cli.server.port) conf.port = cli.server.port; + if (cli.ecoMode) conf.ecoMode = cli.ecoMode if (cli.cpu) conf.cpu = Math.max(0.01, Math.min(1.0, cli.cpu)); if (cli.prefix) conf.prefix = Math.max(ProverConstants.MIN_PEER_ID, Math.min(ProverConstants.MAX_PEER_ID, cli.prefix)); if (cli.logs.http) conf.httplogs = true; diff --git a/test/integration/proof-of-work.js b/test/integration/proof-of-work.js index f2540c6060ede8d045dc4bb3bbb9e9113a160e21..dd507167a895b22c4d7aba1f99f35d43ca280b05 100644 --- a/test/integration/proof-of-work.js +++ b/test/integration/proof-of-work.js @@ -16,13 +16,15 @@ keyring from Key ***/ const intermediateProofs = []; -const NB_CORES_FOR_COMPUTATION = 1 // For simple tests. Can be changed to test multiple cores. +const NB_CORES_FOR_COMPUTATION = 2 // For simple tests. Can be changed to test multiple cores. const prover = new BlockProver({ push: (data) => intermediateProofs.push(data), conf: { + avgGenTime: 20,//1*60, + ecoMode: true, nbCores: NB_CORES_FOR_COMPUTATION, - cpu: 1.0, // 80%, + cpu: 0.8, // 80%, pair: { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP' @@ -34,9 +36,11 @@ const prover = new BlockProver({ const now = 1474382274 * 1000; const MUST_START_WITH_A_ZERO = 16; const MUST_START_WITH_TWO_ZEROS = 32; +const MUST_START_WITH_THREE_ZEROS = 58; describe("Proof-of-work", function() { + this.timeout(6*60000) it('should be able to find an easy PoW', () => co(function*() { let block = yield prover.prove({ issuer: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', @@ -48,6 +52,14 @@ describe("Proof-of-work", function() { intermediateProofs[intermediateProofs.length - 1].pow.should.have.property('hash').equal(block.hash); })); + it('should be reducing cpu when the PoW is too easy for the cpu', () => co(function*() { + for(let i=0; i<8; ++i) { + let block = yield prover.prove({ + issuer: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', + number: i+2 + }, MUST_START_WITH_THREE_ZEROS, now); + } + })); // Too randomly successing test // it('should be able to cancel a proof-of-work on other PoW receival', () => co(function*() { // const now = 1474464489;