diff --git a/app/modules/prover/lib/constants.ts b/app/modules/prover/lib/constants.ts index 0a454d38fd9c85e58115c2f971bbb6cb1cea812e..bb0cfcf31821b76e4a86b066049431d345317613 100644 --- a/app/modules/prover/lib/constants.ts +++ b/app/modules/prover/lib/constants.ts @@ -13,6 +13,7 @@ export const ProverConstants = { NONCE_RANGE: 1000 * 1000 * 1000 * 100, POW_MAXIMUM_ACCEPTABLE_HANDICAP: 64, + POW_NB_PAUSES_PER_ROUND: 10, // When to trigger the PoW process again if no PoW is triggered for a while. In milliseconds. POW_SECURITY_RETRY_DELAY: 10 * 60 * 1000 diff --git a/app/modules/prover/lib/powCluster.ts b/app/modules/prover/lib/powCluster.ts index 140c887a5fa311e5d6ce1aec8f77d4fcb66c5052..f14f9b67efa90b632f99342ce438316417dca398 100644 --- a/app/modules/prover/lib/powCluster.ts +++ b/app/modules/prover/lib/powCluster.ts @@ -15,6 +15,8 @@ let clusterId = 0 */ export class Master { + nbCancels = 0 + clusterId:number currentPromise:any|null = null slaves:any[] = [] @@ -54,6 +56,8 @@ export class Master { this.currentPromise.extras.resolve(message.answer) // Stop the slaves' current work this.cancelWork() + } else if (message.canceled) { + this.nbCancels++ } // this.logger.debug(`ENGINE c#${this.clusterId}#${this.slavesMap[worker.id].index}:`, message) } @@ -130,7 +134,7 @@ export class Master { } cancelWork() { - this.logger.info(`Cancelling the work on PoW cluster`) + this.logger.info(`Cancelling the work on PoW cluster of %s slaves`, this.slaves.length) this.slaves.forEach(s => { s.worker.send({ command: 'cancel' @@ -189,7 +193,8 @@ export class Master { uuid, command: 'newPoW', value: { - block: stuff.newPoW.block, + initialTestsPerRound: stuff.initialTestsPerRound, + maxDuration: stuff.maxDuration,block: stuff.newPoW.block, nonceBeginning: s.nonceBeginning, zeros: stuff.newPoW.zeros, highMark: stuff.newPoW.highMark, diff --git a/app/modules/prover/lib/proof.ts b/app/modules/prover/lib/proof.ts index 02927aac80c5750b1a23c391480d98ae257358c4..caadc5cf69a762090de009d1538ec92527c671c8 100644 --- a/app/modules/prover/lib/proof.ts +++ b/app/modules/prover/lib/proof.ts @@ -74,6 +74,7 @@ function beginNewProofOfWork(stuff:any) { ****************/ let nonce = 0; + const maxDuration = stuff.maxDuration || 1000 const conf = stuff.conf; const block = stuff.block; const nonceBeginning = stuff.nonceBeginning; @@ -101,13 +102,14 @@ function beginNewProofOfWork(stuff:any) { * GO! ****************/ + let pausePeriod = 1; let testsCount = 0; let found = false; let turn = 0; const profiler = new ProcessCpuProfiler(100) let cpuUsage = profiler.cpuUsageOverLastMilliseconds(1) // We limit the number of tests according to CPU usage - let testsPerRound = 1 + let testsPerRound = stuff.initialTestsPerRound || 1 let turnDuration = 20 // We initially goes quickly to the max speed = 50 reevaluations per second (1000 / 20) while (!found && !askedStop) { @@ -178,7 +180,7 @@ function beginNewProofOfWork(stuff:any) { if (!found && !askedStop) { i++; testsCount++; - if (i % testsPerRound === 0) { + if (i % pausePeriod === 0) { await countDown(0); // Very low pause, just the time to process eventual end of the turn } } @@ -191,7 +193,6 @@ function beginNewProofOfWork(stuff:any) { // CPU speed recording if (turn > 0) { - const oldTestsPerRound = testsPerRound cpuUsage = profiler.cpuUsageOverLastMilliseconds(turnDuration) if (cpuUsage > currentCPU + 0.005 || cpuUsage < currentCPU - 0.005) { let powVariationFactor @@ -203,6 +204,7 @@ function beginNewProofOfWork(stuff:any) { powVariationFactor = 0.99 testsPerRound = Math.max(1, Math.floor(testsPerRound * powVariationFactor)) } + pausePeriod = Math.floor(testsPerRound / ProverConstants.POW_NB_PAUSES_PER_ROUND) } } @@ -222,7 +224,7 @@ function beginNewProofOfWork(stuff:any) { turn++ turnDuration += 1 - turnDuration = Math.min(turnDuration, 1000) // Max 1 second per turn + turnDuration = Math.min(turnDuration, maxDuration) // Max 1 second per turn } /***************** @@ -236,6 +238,7 @@ function beginNewProofOfWork(stuff:any) { // PoW stopped askedStop = false; + pSend({ canceled: true }) return null } else { diff --git a/test/fast/prover/pow-1-cluster.js b/test/fast/prover/pow-1-cluster.ts similarity index 64% rename from test/fast/prover/pow-1-cluster.js rename to test/fast/prover/pow-1-cluster.ts index 96d58c12b9f36dd1391c91d3b649bb4f12f25bbc..a225f880d287786dca8153dd42e5832c73782621 100644 --- a/test/fast/prover/pow-1-cluster.js +++ b/test/fast/prover/pow-1-cluster.ts @@ -1,16 +1,15 @@ -"use strict"; +import {Master} from "../../../app/modules/prover/lib/powCluster" const co = require('co') -const should = require('should') -const PowCluster = require('../../../app/modules/prover/lib/powCluster').Master +require('should') const logger = require('../../../app/lib/logger').NewLogger() -let master +let master:Master describe('PoW Cluster', () => { before(() => { - master = new PowCluster(1, logger) + master = new Master(1, logger) }) it('should have an empty cluster if no PoW was asked', () => { @@ -73,4 +72,35 @@ describe('PoW Cluster', () => { delay.should.be.below(50) })) + it('should be able to stop all the cores on cancel', async () => { + master.proveByWorkers({ + initialTestsPerRound: 100, + maxDuration: 1000, + newPoW: { + block: { + number: 0 + }, + zeros: 10, + highMark: 'F', + conf: { + medianTimeBlocks: 1, + avgGenTime: 100, + cpu: 0.8, + prefix: '8', + nbCores: 1 + }, + pair: { + pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', + sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP' + } + } + }) + await new Promise(res => { + master.onInfoMessage = () => res() + }) + await master.cancelWork() + await new Promise(res => setTimeout(res, 100)) + master.nbCancels.should.equal(1) + }) + });