diff --git a/app/lib/dal/fileDAL.ts b/app/lib/dal/fileDAL.ts index e7f5794ead30ca5aae57501f89fd9a441f5b5e6c..d4a5d7481923c17816907793556a4f8a70cf434c 100644 --- a/app/lib/dal/fileDAL.ts +++ b/app/lib/dal/fileDAL.ts @@ -16,6 +16,7 @@ import {DBMembership} from "./sqliteDAL/MembershipDAL" import {MerkleDTO} from "../dto/MerkleDTO" import {CommonConstants} from "../common-libs/constants" import { ProxiesConf } from '../proxy'; +import {PowDAL} from "./fileDALs/PowDAL"; const fs = require('fs') const path = require('path') @@ -40,6 +41,7 @@ export class FileDAL { wotb:any profile:string + powDAL:PowDAL confDAL:any metaDAL:any peerDAL:any @@ -68,6 +70,7 @@ export class FileDAL { this.profile = 'DAL' // DALs + this.powDAL = new PowDAL(this.rootPath, this.myFS) this.confDAL = new ConfDAL(this.rootPath, this.myFS) this.metaDAL = new (require('./sqliteDAL/MetaDAL').MetaDAL)(this.sqliteDriver); this.peerDAL = new (require('./sqliteDAL/PeerDAL').PeerDAL)(this.sqliteDriver); @@ -85,6 +88,7 @@ export class FileDAL { this.cindexDAL = new (require('./sqliteDAL/index/CIndexDAL').CIndexDAL)(this.sqliteDriver); this.newDals = { + 'powDAL': this.powDAL, 'metaDAL': this.metaDAL, 'blockDAL': this.blockDAL, 'certDAL': this.certDAL, diff --git a/app/lib/dal/fileDALs/PowDAL.ts b/app/lib/dal/fileDALs/PowDAL.ts new file mode 100644 index 0000000000000000000000000000000000000000..6a3d0102a6b5eb6986da81cc038bf34043526efc --- /dev/null +++ b/app/lib/dal/fileDALs/PowDAL.ts @@ -0,0 +1,22 @@ +import {AbstractCFS} from "./AbstractCFS" + +export class PowDAL extends AbstractCFS { + + private static POW_FILE = "pow.txt" + + constructor(rootPath:string, qioFS:any) { + super(rootPath, qioFS) + } + + init() { + return this.coreFS.remove(PowDAL.POW_FILE, false).catch(() => {}) + } + + async getCurrent() { + return await this.coreFS.read(PowDAL.POW_FILE); + } + + async writeCurrent(current:string) { + await this.coreFS.write(PowDAL.POW_FILE, current, false); + } +} diff --git a/app/lib/dto/ConfDTO.ts b/app/lib/dto/ConfDTO.ts index 2e77e92fc70336c82b99bbb7b908ee9251918d09..f9405f1f4efbbe7a2017f8dee565dea38be47854 100644 --- a/app/lib/dto/ConfDTO.ts +++ b/app/lib/dto/ConfDTO.ts @@ -8,6 +8,10 @@ export interface Keypair { sec: string } +export interface PowDTO { + powNoSecurity:boolean +} + export interface BranchingDTO { switchOnHeadAdvance:number avgGenTime:number @@ -82,7 +86,7 @@ export interface WS2PConfDTO { } } -export class ConfDTO implements CurrencyConfDTO, KeypairConfDTO, NetworkConfDTO, BranchingDTO, WS2PConfDTO { +export class ConfDTO implements CurrencyConfDTO, KeypairConfDTO, NetworkConfDTO, BranchingDTO, WS2PConfDTO, PowDTO { constructor( public loglevel: string, @@ -158,7 +162,8 @@ export class ConfDTO implements CurrencyConfDTO, KeypairConfDTO, NetworkConfDTO, privilegedOnly: boolean maxPublic?:number maxPrivate?:number - } + }, + public powNoSecurity = false ) {} static mock() { diff --git a/app/lib/system/directory.ts b/app/lib/system/directory.ts index 3846c4b8b0aee27b91743164c4574506e03ad7c8..2c1a4d658347aca032e727dda062a01a69e0f1f7 100644 --- a/app/lib/system/directory.ts +++ b/app/lib/system/directory.ts @@ -28,7 +28,7 @@ const dir = module.exports = { getHome: (profile:string|null = null, directory:string|null = null) => getHomePath(profile, directory), - getHomeFS: async (isMemory:boolean, theHome:string) => { + getHomeFS: async (isMemory:boolean, theHome:string, makeTree = true) => { const home = theHome || dir.getHome(); const params:any = { home: home @@ -38,7 +38,9 @@ const dir = module.exports = { } else { params.fs = qfs; } - await params.fs.makeTree(home); + if (makeTree) { + await params.fs.makeTree(home) + } return params; }, diff --git a/app/modules/prover/lib/PowWorker.ts b/app/modules/prover/lib/PowWorker.ts index fd225941a7b8897a0c6f5046ec4dd25fea603ba7..bb0b73b000e1fff991045bdd7f6899539d85da13 100644 --- a/app/modules/prover/lib/PowWorker.ts +++ b/app/modules/prover/lib/PowWorker.ts @@ -79,7 +79,7 @@ export class PowWorker { return this.proofPromise } - sendConf(confMessage:{ command:string, value:any }) { + sendConf(confMessage:{ rootPath: string, command:string, value:any }) { this.nodejsWorker.send(confMessage) } diff --git a/app/modules/prover/lib/blockProver.ts b/app/modules/prover/lib/blockProver.ts index 32d5699ecc014e8ec690c6b5b98722d43b864a6a..93647b3b1c035658a309b2b9e11cd7371511e969 100644 --- a/app/modules/prover/lib/blockProver.ts +++ b/app/modules/prover/lib/blockProver.ts @@ -22,7 +22,7 @@ export class WorkerFarm { constructor(private server:Server, private logger:any) { - this.theEngine = new PowEngine(server.conf, server.logger) + this.theEngine = new PowEngine(server.conf, server.logger, server.dal) // An utility method to filter the pow notifications this.checkPoWandNotify = (hash:string, block:DBBlock, found:boolean) => { @@ -132,12 +132,7 @@ export class BlockProver { // If no farm was instanciated, there is nothing to do yet if (this.workerFarmPromise) { let farm = await this.getWorker(); - if (farm.isComputing() && !farm.isStopping()) { - await farm.stopPoW() - } else { - // We force the stop anyway, just to be sure - await farm.stopPoW() - } + await farm.stopPoW() if (this.waitResolve) { this.waitResolve(); this.waitResolve = null; @@ -179,6 +174,7 @@ export class BlockProver { let result = await powFarm.askNewProof({ newPoW: { conf: { + powNoSecurity: this.conf.powNoSecurity, cpu: this.conf.cpu, prefix: this.conf.prefix, avgGenTime: this.conf.avgGenTime, diff --git a/app/modules/prover/lib/engine.ts b/app/modules/prover/lib/engine.ts index 0f42ec11ea6b866fe929f0d690232134fd4cea97..883e9a6f1b507ed72875ae5eec9d07eddf5a2693 100644 --- a/app/modules/prover/lib/engine.ts +++ b/app/modules/prover/lib/engine.ts @@ -1,5 +1,6 @@ import {Master as PowCluster} from "./powCluster" import {ConfDTO} from "../../../lib/dto/ConfDTO" +import {FileDAL} from "../../../lib/dal/fileDAL"; const os = require('os') @@ -16,11 +17,11 @@ export class PowEngine { private cluster:PowCluster readonly id:number - constructor(private conf:ConfDTO, logger:any) { + constructor(private conf:ConfDTO, logger:any, private dal?:FileDAL) { // We use as much cores as available, but not more than CORES_MAXIMUM_USE_IN_PARALLEL this.nbWorkers = conf.nbCores - this.cluster = new PowCluster(this.nbWorkers, logger) + this.cluster = new PowCluster(this.nbWorkers, logger, dal) this.id = this.cluster.clusterId } @@ -33,7 +34,7 @@ export class PowEngine { } async prove(stuff:any) { - this.cluster.cancelWork() + 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 d0c64c4e422ff0d95111d2d2f491e97d38a06967..069bfba8fd1b493f153990da33646fa97b0ce3dd 100644 --- a/app/modules/prover/lib/powCluster.ts +++ b/app/modules/prover/lib/powCluster.ts @@ -2,6 +2,7 @@ import {ConfDTO} from "../../../lib/dto/ConfDTO" import {ProverConstants} from "./constants" import {createPowWorker} from "./proof" import {PowWorker} from "./PowWorker" +import {FileDAL} from "../../../lib/dal/fileDAL"; const _ = require('underscore') const nuuid = require('node-uuid'); @@ -36,7 +37,7 @@ export class Master { onInfoCallback:any workersOnline:Promise<any>[] - constructor(private nbCores:number, logger:any) { + constructor(private nbCores:number, logger:any, private dal?:FileDAL) { this.clusterId = clusterId++ this.logger = logger || Master.defaultLogger() this.onInfoMessage = (message:any) => { @@ -83,6 +84,7 @@ export class Master { }, () => { this.logger.info(`[online] worker c#${this.clusterId}#w#${index}`) worker.sendConf({ + rootPath: this.dal ? this.dal.rootPath : '', command: 'conf', value: this.conf }) @@ -119,6 +121,7 @@ export class Master { this.conf.prefix = this.conf.prefix || conf.prefix this.slaves.forEach(s => { s.worker.sendConf({ + rootPath: '', command: 'conf', value: this.conf }) @@ -130,11 +133,15 @@ export class Master { this.slaves.forEach(s => { s.worker.sendCancel() }) + if (this.dal) { + this.dal.powDAL.writeCurrent("") + } } async cancelWork() { - this.cancelWorkersWork() const workEnded = this.currentPromise + // Don't await the cancellation! + this.cancelWorkersWork() // Current promise is done this.currentPromise = null return await workEnded @@ -150,13 +157,17 @@ export class Master { this.slaves = [] } - proveByWorkers(stuff:any) { + async proveByWorkers(stuff:any) { // Eventually spawn the workers if (this.slaves.length === 0) { this.initCluster() } + if (this.dal) { + await this.dal.powDAL.writeCurrent([stuff.newPoW.block.number - 1, stuff.newPoW.block.previousHash].join('-')) + } + // Register the new proof uuid const uuid = nuuid.v4() this.currentPromise = querablep((async () => { @@ -173,14 +184,17 @@ export class Master { uuid, command: 'newPoW', value: { + rootPath: this.dal ? this.dal.rootPath : '', initialTestsPerRound: stuff.initialTestsPerRound, - maxDuration: stuff.maxDuration,block: stuff.newPoW.block, + maxDuration: stuff.maxDuration, + block: stuff.newPoW.block, nonceBeginning: s.nonceBeginning, zeros: stuff.newPoW.zeros, highMark: stuff.newPoW.highMark, pair: _.clone(stuff.newPoW.pair), forcedTime: stuff.newPoW.forcedTime, conf: { + powNoSecurity: stuff.newPoW.conf.powNoSecurity, medianTimeBlocks: stuff.newPoW.conf.medianTimeBlocks, avgGenTime: stuff.newPoW.conf.avgGenTime, cpu: stuff.newPoW.conf.cpu, @@ -197,6 +211,7 @@ export class Master { // Find a proof const result = await Promise.race(asks) + // Don't await the cancellation! this.cancelWorkersWork() // Wait for all workers to have stopped looking for a proof await Promise.all(asks) diff --git a/app/modules/prover/lib/proof.ts b/app/modules/prover/lib/proof.ts index c08fde11ed3dc6132a2773d73a9994c075b58a2d..855adb169858a77118674f622885e2868cba953f 100644 --- a/app/modules/prover/lib/proof.ts +++ b/app/modules/prover/lib/proof.ts @@ -7,12 +7,15 @@ import {KeyGen} from "../../../lib/common-libs/crypto/keyring" import {dos2unix} from "../../../lib/common-libs/dos2unix" import {rawer} from "../../../lib/common-libs/index" import {ProcessCpuProfiler} from "../../../ProcessCpuProfiler" +import {PowDAL} from "../../../lib/dal/fileDALs/PowDAL"; const moment = require('moment'); const querablep = require('querablep'); +const directory = require('../../../lib/system/directory'); export function createPowWorker() { + let powDAL:PowDAL|null = null let computing = querablep(Promise.resolve(null)); let askedStop = false; @@ -47,6 +50,11 @@ export function createPowWorker() { await computing; } + if (message.value.rootPath) { + const params = await directory.getHomeFS(false, message.value.rootPath, false) + powDAL = new PowDAL(message.value.rootPath, params.fs) + } + const res = await beginNewProofOfWork(message.value); answer(message, res); })() @@ -226,6 +234,22 @@ export function createPowWorker() { })() ]); + // console.log('W#%s.powDAL = ', process.pid, powDAL) + + if (powDAL && !conf.powNoSecurity) { + const currentProofCheck = await powDAL.getCurrent() + if (currentProofCheck !== null) { + if (currentProofCheck === "") { + askedStop = true + } else { + const [currentNumber, currentHash] = currentProofCheck.split('-') + if (block.number !== parseInt(currentNumber) + 1 || block.previousHash !== currentHash) { + askedStop = true + } + } + } + } + // Next turn turn++ diff --git a/test/integration/server-import-export.js b/test/integration/server-import-export.js index 4c56854060f461cae02c95fa7b4629b40e4b9966..0f3ab4344bfbdf3981dc90bc837ad2434b082c25 100644 --- a/test/integration/server-import-export.js +++ b/test/integration/server-import-export.js @@ -21,10 +21,10 @@ let s0, s1; describe('Import/Export', () => { before(() => co(function *() { - s0 = toolbox.server(_.extend({ homename: 'dev_unit_tests1' }, serverConfig)); + s0 = toolbox.server(_.extend({ homename: 'dev_unit_tests1', powNoSecurity: true }, serverConfig)); yield s0.resetHome(); - s1 = toolbox.server(_.extend({ homename: 'dev_unit_tests1' }, serverConfig)); + s1 = toolbox.server(_.extend({ homename: 'dev_unit_tests1', powNoSecurity: true }, serverConfig)); const cat = new TestUser('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 }); const tac = new TestUser('tac', { pub: '2LvDg21dVXvetTD9GdkPLURavLYEqP3whauvPWX4c2qc', sec: '2HuRLWgKgED1bVio1tdpeXrf7zuUszv1yPHDsDj7kcMC4rVSN9RC58ogjtKNfTbH1eFz7rn38U1PywNs3m6Q7UxE'}, { server: s1 }); @@ -53,8 +53,6 @@ describe('Import/Export', () => { return new Promise((resolve, reject) => { archive.on('error', reject); output.on('close', function() { - console.log(archive.pointer() + ' total bytes'); - console.log('archiver has been finalized and the output file descriptor has closed.'); resolve(); }); });