From a3739d9e4d1485257d909017be9c1e69f8a8873f Mon Sep 17 00:00:00 2001 From: MiaoWoo Date: Wed, 17 Jul 2019 00:13:22 +0800 Subject: [PATCH] feat: 1120 release c/s mode complete Signed-off-by: MiaoWoo --- package.json | 10 +- public/index.html | 92 +++++++++++++++++ src/core/block-exchange.ts | 26 ++++- src/core/connect.ts | 6 +- src/core/transfer-msg.ts | 9 +- src/process/main-process.ts | 32 ++++-- src/process/pow-process.ts | 198 ++++++++++++++++++++++-------------- src/rpc/client.ts | 20 ++++ src/rpc/server.ts | 94 +++++++++++++++++ src/run-client.ts | 68 +++++++++++++ tsconfig.json | 4 +- 11 files changed, 461 insertions(+), 98 deletions(-) create mode 100644 public/index.html create mode 100644 src/rpc/client.ts create mode 100644 src/rpc/server.ts create mode 100644 src/run-client.ts diff --git a/package.json b/package.json index bc46c7f..dbed215 100644 --- a/package.json +++ b/package.json @@ -23,20 +23,26 @@ "start": "node dist/run-node.js" }, "dependencies": { + "@cc-server/core": "^0.6.1", + "@cc-server/ws": "^0.6.1", "bintrees": "^1.0.2", "greenlock": "^2.6.7", "ntp-client": "^0.5.3", "secp256k1": "^3.6.1", + "socket.io-client": "^2.2.0", "stun": "^1.1.0", "uglify-js": "^3.4.9", "zip": "^1.2.0" }, "devDependencies": { "@types/bintrees": "^1.0.2", - "@types/secp256k1": "^3.5.0", + "@types/express": "^4.17.0", "@types/node": "^12.6.1", + "@types/secp256k1": "^3.5.0", + "@types/socket.io": "^2.1.2", + "@types/socket.io-client": "^1.4.32", "rimraf": "^2.6.3", "ts-node-dev": "^1.0.0-pre.40", "typescript": "^3.5.3" } -} \ No newline at end of file +} diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..bac7333 --- /dev/null +++ b/public/index.html @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/src/core/block-exchange.ts b/src/core/block-exchange.ts index de70d70..d4ce933 100644 --- a/src/core/block-exchange.ts +++ b/src/core/block-exchange.ts @@ -12,6 +12,7 @@ import CBlock from './block-loader' import { RBTree } from './library' import { STreeBuffer } from './base'; +import { SendToWebClient } from '../rpc/server' require('./library'); require('./crypto-library'); const TX_PROCESS_TIME = 100; @@ -423,8 +424,7 @@ export default class CConsensus extends CBlock { var SendData = { "Method": "RETTRANSFERTX", "Context": Info.Context, "Data": { BlockNum: Block.BlockNum, Array: Arr, } }; this.SendF(Node, SendData, global.MAX_BLOCK_SIZE + 1000) } - static - RETTRANSFERTX_F() { + static RETTRANSFERTX_F() { return "{BlockNum:uint,Array:[{body:tr}]}"; } RETTRANSFERTX(Info, CurTime) { @@ -639,8 +639,7 @@ export default class CConsensus extends CBlock { var BufWrite = global.BufLib.GetBufferFromObject(Data, FORMAT_DATA_TRANSFER, global.MAX_BLOCK_SIZE + 30000, WorkStructSend); return BufWrite; } - static - TRANSFER_F() { + static TRANSFER_F() { return FORMAT_DATA_TRANSFER; } CheckingMaxPowOther(Block) { @@ -1392,6 +1391,25 @@ export default class CConsensus extends CBlock { this.AddToMaxPOW(BlockMining, { SeqHash: BlockMining.SeqHash, AddrHash: BlockMining.AddrHash, PrevHash: BlockMining.PrevHash, TreeHash: BlockMining.TreeHash, }) + if (bWas == 3) { + setTimeout(() => { + let webmsg: any = { BlockNum: msg.BlockNum } + webmsg.Mining = { + Hash: BlockMining.Hash.toString(), + SeqHash: BlockMining.Hash.toString() + } + webmsg.New = { + Hash: ValueNew.Hash.toString(), + PowHash: ValueNew.PowHash.toString() + } + Object.assign(webmsg, { + HashCount, + Power, + Num: msg.Num + }) + SendToWebClient(webmsg) + }, 1) + } } } }; diff --git a/src/core/connect.ts b/src/core/connect.ts index f45f428..49bebc1 100644 --- a/src/core/connect.ts +++ b/src/core/connect.ts @@ -275,8 +275,7 @@ export default class CConnect extends CMessages { NetConstant:{Num:uint,BlockNum:uint,MaxTrasactionLimit:uint,Reserv1:uint,Reserv2:uint,Reserv3:uint,Reserv4:uint,Reserv5:uint,Sign:arr64},\ }"; } - static - PONG_F(bSend) { + static PONG_F(bSend) { return CConnect.PING_F(bSend); } PING(Info, CurTime) { @@ -914,8 +913,7 @@ export default class CConnect extends CMessages { global.SAVE_CONST(true) } } - static - TIME_F() { + static TIME_F() { return "{Time:uint, Sign:arr64}"; } SendTimeDev(Node) { diff --git a/src/core/transfer-msg.ts b/src/core/transfer-msg.ts index 88faa9c..901f321 100644 --- a/src/core/transfer-msg.ts +++ b/src/core/transfer-msg.ts @@ -88,8 +88,7 @@ export default class CMessages extends CSmartContract { } return true; } - static - MESSAGE_F() { + static MESSAGE_F() { return "{Arr:[{addrArr:hash,body:tr,nonce:uint,time:uint}]}"; } MESSAGE(Info, CurTime) { @@ -161,8 +160,7 @@ export default class CMessages extends CSmartContract { return - 5; if (Block.Active) { Res = - 3 - } - else { + } else { Res = this.AddTrToBlockQuote(Block, Tr) if (Tr.ToAll) this.SendTransaction(Tr) @@ -200,8 +198,7 @@ export default class CMessages extends CSmartContract { break; } } - static - TRANSACTION_F() { + static TRANSACTION_F() { return "{body:tr}"; } TRANSACTION(Info, CurTime) { diff --git a/src/process/main-process.ts b/src/process/main-process.ts index 8ae6133..354d2cf 100644 --- a/src/process/main-process.ts +++ b/src/process/main-process.ts @@ -14,13 +14,12 @@ import * as fs from 'fs' import * as os from 'os' import * as crypto from 'crypto'; global.START_SERVER = 1; -import { secp256k1 } from '../core/library' - +import { WsServer, SendToClient } from '../rpc/server' global.DATA_PATH = global.GetNormalPathString(global.DATA_PATH); global.CODE_PATH = global.GetNormalPathString(global.CODE_PATH); console.log("DATA DIR: " + global.DATA_PATH); console.log("PROGRAM DIR: " + global.CODE_PATH); -import "../core/library" +import { secp256k1 } from '../core/library' global.ToLog(os.platform() + " (" + os.arch() + ") " + os.release()); var VerArr = process.versions.node.split('.'); global.ToLog("nodejs: " + process.versions.node); @@ -393,6 +392,7 @@ function AllAlive() { for (var i = 0; i < global.ArrMiningWrk.length; i++) { global.ArrMiningWrk[i].send({ cmd: "Alive" }); } + SendToClient({ cmd: "Alive" }) }; function ClearArrMining() { @@ -479,18 +479,20 @@ function RunStopPOWProcess(Mode) { Worker.on('message', function(msg) { if (msg.cmd === "log") { global.ToLog(msg.message); - } - else + } else { if (msg.cmd === "online") { Worker.bOnline = true; global.ToLog("RUNNING PROCESS:" + Worker.Num + ":" + msg.message); - } else + } else { if (msg.cmd === "POW") { global.SERVER.MiningProcess(msg); - } else + } else { if (msg.cmd === "HASHRATE") { global.ADD_HASH_RATE(msg.CountNonce); } + } + } + } }); Worker.on('error', function(err) { if (!global.ArrMiningWrk.length) @@ -510,6 +512,21 @@ function RunStopPOWProcess(Mode) { }; function SetCalcPOW(Block, cmd) { + SendToClient({ + cmd: cmd, + BlockNum: Block.BlockNum, + Account: global.GENERATE_BLOCK_ACCOUNT, + MinerID: global.GENERATE_BLOCK_ACCOUNT, + SeqHash: Block.SeqHash, + Hash: Block.Hash, + PrevHash: Block.PrevHash, + Time: Date.now(), + RunPeriod: global.POWRunPeriod, + RunCount: global.POW_RUN_COUNT, + Percent: global.POW_MAX_PERCENT, + CountMiningCPU: global.GetCountMiningCPU(), + ProcessMemorySize: ProcessMemorySize, + }) if (!global.USE_MINING) return; if (global.ArrMiningWrk.length !== global.GetCountMiningCPU()) @@ -653,6 +670,7 @@ function RunOnce() { require("../core/update"); global.RunOnUpdate(); StartAllProcess(1); + WsServer.start(8080); // require("./dogs"); if (global.RESTART_PERIOD_SEC) { var Period = (global.random(600) + global.RESTART_PERIOD_SEC); diff --git a/src/process/pow-process.ts b/src/process/pow-process.ts index 55cafb2..a59850d 100644 --- a/src/process/pow-process.ts +++ b/src/process/pow-process.ts @@ -16,14 +16,6 @@ import { CreatePOWVersionX } from "../core/terahashmining" var PROCESS = process; if (process.send && !global.DEBUGPROCESS) { process.send({ cmd: "online", message: "OK" }); - global.ToLogClient = function(Str, StrKey, bFinal) { - process.send({ - cmd: "ToLogClient", - Str: "" + Str, - StrKey: StrKey, - bFinal: bFinal - }); - }; } else { PROCESS = global.DEBUGPROCESS; } @@ -31,51 +23,99 @@ var LastAlive = Date.now(); setInterval(CheckAlive, 1000); var idInterval = undefined; var Block: any = {}; + +import { powClient } from '../rpc/client' + +powClient.on('message', (msg) => { + LastAlive = Date.now(); + switch (msg.cmd) { + case "FastCalcBlock": + FastCalcBlock(msg); + break; + case "Alive": + break; + case "Exit": + PROCESS.exit(0); + } +}) +powClient.connect() + +function FastCalcBlock(msg) { + var FastBlock = msg; + StartHashPump(FastBlock); + FastBlock.RunCount = 0; + try { + if (CreatePOWVersionX(FastBlock)) { + powClient.send({ + cmd: "POW", + BlockNum: FastBlock.BlockNum, + SeqHash: FastBlock.SeqHash, + Hash: FastBlock.Hash, + PowHash: FastBlock.PowHash, + AddrHash: FastBlock.AddrHash, + Num: FastBlock.Num + }); + } + } catch (e) { + powClient.emit('web', `FastCalcBlock Error ${e}...`) + global.ToError(e); + } +} PROCESS.on('message', function(msg) { LastAlive = Date.now(); - if (msg.cmd === "FastCalcBlock") { - var FastBlock = msg; - StartHashPump(FastBlock); - FastBlock.RunCount = 0; - try { - if (CreatePOWVersionX(FastBlock)) - process.send({ - cmd: "POW", - BlockNum: FastBlock.BlockNum, - SeqHash: FastBlock.SeqHash, - Hash: FastBlock.Hash, - PowHash: FastBlock.PowHash, - AddrHash: FastBlock.AddrHash, - Num: FastBlock.Num - }); - } catch (e) { - global.ToError(e); - } - } else - if (msg.cmd === "SetBlock") { - var StartNonce = 1000000 * (1 + msg.Num); - if (Block.HashCount) { - process.send({ cmd: "HASHRATE", CountNonce: Block.HashCount, Hash: Block.Hash }); - } - Block.HashCount = 0; - Block = msg; - Block.Time = Date.now(); - Block.LastNonce = StartNonce; - Block.Period = global.CONSENSUS_PERIOD_TIME * Block.Percent / 100; - if (Block.Period > 0 && Block.RunPeriod > 0) { - CalcPOWHash(); - if (idInterval !== undefined) { - clearInterval(idInterval); - } - idInterval = setInterval(CalcPOWHash, Block.RunPeriod); - } - } else - if (msg.cmd === "Alive") { - } else - if (msg.cmd === "Exit") { - PROCESS.exit(0); - } -}); + switch (msg.cmd) { + case "Alive": + break; + case "Exit": + PROCESS.exit(0); + } +}) +// PROCESS.on('message', function(msg) { +// LastAlive = Date.now(); +// if (msg.cmd === "FastCalcBlock") { +// var FastBlock = msg; +// StartHashPump(FastBlock); +// FastBlock.RunCount = 0; +// try { +// if (CreatePOWVersionX(FastBlock)) +// process.send({ +// cmd: "POW", +// BlockNum: FastBlock.BlockNum, +// SeqHash: FastBlock.SeqHash, +// Hash: FastBlock.Hash, +// PowHash: FastBlock.PowHash, +// AddrHash: FastBlock.AddrHash, +// Num: FastBlock.Num +// }); +// } catch (e) { +// global.ToError(e); +// } +// } else { +// if (msg.cmd === "SetBlock") { +// var StartNonce = 1000000 * (1 + msg.Num); +// if (Block.HashCount) { +// process.send({ cmd: "HASHRATE", CountNonce: Block.HashCount, Hash: Block.Hash }); +// } +// Block.HashCount = 0; +// Block = msg; +// Block.Time = Date.now(); +// Block.LastNonce = StartNonce; +// Block.Period = global.CONSENSUS_PERIOD_TIME * Block.Percent / 100; +// if (Block.Period > 0 && Block.RunPeriod > 0) { +// CalcPOWHash(); +// if (idInterval !== undefined) { +// clearInterval(idInterval); +// } +// idInterval = setInterval(CalcPOWHash, Block.RunPeriod); +// } +// } else +// if (msg.cmd === "Alive") { +// } else +// if (msg.cmd === "Exit") { +// PROCESS.exit(0); +// } +// } +// }); function CheckAlive() { if (global.NOALIVE) @@ -87,29 +127,32 @@ function CheckAlive() { } }; -function CalcPOWHash() { - if (!Block.SeqHash) - return; - if ((new Date() as any) - Block.Time > Block.Period) { - clearInterval(idInterval); - idInterval = undefined; - return; - } - try { - if (CreatePOWVersionX(Block)) - process.send({ - cmd: "POW", - BlockNum: Block.BlockNum, - SeqHash: Block.SeqHash, - Hash: Block.Hash, - PowHash: Block.PowHash, - AddrHash: Block.AddrHash, - Num: Block.Num - }); - } catch (e) { - global.ToError(e); - } -}; +// function CalcPOWHash() { +// if (!Block.SeqHash) +// return; +// if ((new Date() as any) - Block.Time > Block.Period) { +// clearInterval(idInterval); +// idInterval = undefined; +// return; +// } +// try { +// if (CreatePOWVersionX(Block)) { +// let msg = { +// cmd: "POW", +// BlockNum: Block.BlockNum, +// SeqHash: Block.SeqHash, +// Hash: Block.Hash, +// PowHash: Block.PowHash, +// AddrHash: Block.AddrHash, +// Num: Block.Num +// } +// powClient.send(msg) +// //process.send(msg); +// } +// } catch (e) { +// global.ToError(e); +// } +// }; global.BlockPump = undefined; var idIntervalPump = undefined; @@ -124,6 +167,7 @@ function StartHashPump(SetBlock) { MinerID: SetBlock.MinerID, Percent: SetBlock.Percent, LastNonce: 0, + Num: SetBlock.Num, }; } if (!idIntervalPump) { @@ -144,6 +188,12 @@ function PumpHash() { EndTime = CurTime; return; } + if (global.BlockPump.RunCount) { + setTimeout(() => { + powClient.send({ cmd: "HASHRATE", CountNonce: global.BlockPump.RunCount }); + }, 1) + } + global.BlockPump.LastNonce = global.BlockPump.LastNonce + global.BlockPump.Num * 100000 CreatePOWVersionX(global.BlockPump, 1); } else { var Delta = CurTime - EndTime; diff --git a/src/rpc/client.ts b/src/rpc/client.ts new file mode 100644 index 0000000..8eab9dd --- /dev/null +++ b/src/rpc/client.ts @@ -0,0 +1,20 @@ +import * as io from 'socket.io-client' + +let host = process.env.TERA_HOST || 'http://127.0.0.1:8080/main' + +let powClient = io(host, { + path: '/ws' +}) + +powClient.on('connect', () => { + // console.log(`Client ${powClient.id} connect ...`) + powClient.emit('powclient', {}) + powClient.emit('web', `Connect to ${host} Successful...`) + powClient.send({ cmd: "online", message: "OK" }) +}); + +powClient.on('disconnect', (error) => { + console.log(`Client disconnect Error: ${error}...`) +}); + +export { powClient } diff --git a/src/rpc/server.ts b/src/rpc/server.ts new file mode 100644 index 0000000..5f0132c --- /dev/null +++ b/src/rpc/server.ts @@ -0,0 +1,94 @@ +import { CcServerBoot } from '@cc-server/core' +import { namespace, listener, io, TYPE, interfaces } from '@cc-server/ws' +import { Namespace } from 'socket.io'; +import { Container } from 'inversify'; + +let pows: io.Socket[] = []; + +@namespace('/main') +class TeraNamespace implements interfaces.Namespace { + nsp: Namespace; + @listener() + webclient(socket: io.Socket) { + socket.join('web'); + global.ToLog(`${socket.id} WebClient Connected...`) + } + @listener() + web(socket: io.Socket, msg: any) { + socket.to('web').send('Recover From Pow: ' + JSON.stringify(msg)) + } + @listener() + webmsg(socket: io.Socket, msg: any) { + global.ToLog(`Recover webmsg ${JSON.stringify(msg)}`) + switch (msg.cmd) { + case "list": + socket.send(`Client List:`) + let index = 0; + for (let id in pows) { + const pow = pows[id]; + socket.send(`${index} => ${pow.id}: ${pow.conn.remoteAddress}`) + index++ + } + break; + case "pow": + socket.send('Join Pow Room...') + socket.join('pow') + break; + case "leavepow": + socket.leave('pow') + socket.send('Leave Pow Room...') + break; + } + } + @listener() + powclient(socket: io.Socket) { + pows[socket.id] = socket; + // global.ToLog(`${socket.id} PowClient Connected...`) + } + @listener() + message(socket: io.Socket, msg: any) { + socket.to('pow').send(`${JSON.stringify(msg)}`) + switch (msg.cmd) { + case "POW": + global.SERVER.MiningProcess(msg); + break; + case "HASHRATE": + global.ADD_HASH_RATE(msg.CountNonce); + break; + } + } + disconnect(socket: io.Socket) { + // socket.to('web').send(`Client ${socket.id} ${socket.conn.remoteAddress} disconnect...`) + delete pows[socket.id] + } +} + +let container = new Container(); +let WsServer = new CcServerBoot(container).build(); + +function getServer(): TeraNamespace { + return container.getNamed(TYPE.Namespace, TeraNamespace.name); +} + +function getNamespace(): Namespace { + return getServer().nsp; +} + +function SendToClient(msg: any) { + getNamespace().to('pow').send(JSON.stringify(msg)) + let index = 0; + for (let id in pows) { + const pow = pows[id]; + if (typeof msg === "object") { + msg.Num = index; + } + pow.send(msg) + index++ + } +} + +function SendToWebClient(msg: any) { + getNamespace().to('web').send(msg) +} + +export { WsServer, SendToClient, SendToWebClient } diff --git a/src/run-client.ts b/src/run-client.ts new file mode 100644 index 0000000..205124c --- /dev/null +++ b/src/run-client.ts @@ -0,0 +1,68 @@ +let thread = parseInt(process.env.TERA_THREAD) || 1; +let Memory = thread * 4 * 1024 * 1024 * 1024 +let ProcessMemorySize = Math.trunc(Memory / thread); +import { fork } from 'child_process' +import './core/constant' +import './core/library' + +function Fork(Path, ArrArgs?): TeraChildProcess { + ArrArgs = ArrArgs || []; + if (global.LOCAL_RUN) + ArrArgs.push("LOCALRUN"); + else + if (global.TEST_NETWORK) + ArrArgs.push("TESTRUN"); + ArrArgs.push("PATH:" + global.DATA_PATH); + ArrArgs.push("HOSTING:" + global.HTTP_HOSTING_PORT); + if (!global.USE_PARAM_JS) + ArrArgs.push("NOPARAMJS"); + if (global.NWMODE) + ArrArgs.push("NWMODE"); + if (global.NOALIVE) + ArrArgs.push("NOALIVE"); + if (global.DEV_MODE) + ArrArgs.push("DEV_MODE"); + var execArgv = []; + var Worker = fork(Path, ArrArgs, { execArgv: execArgv }); + return Worker as any; +}; + +let ArrMiningWrk = [] + +function RunProcess() { + for (var R = 0; R < thread; R++) { + let Worker = Fork('./process/pow-process'); + ArrMiningWrk.push(Worker); + Worker.Num = ArrMiningWrk.length; + Worker.on('message', function(msg) { + switch (msg.cmd) { + case "log": + console.log(msg.message) + break; + } + }); + Worker.on('error', function(err) { + if (!ArrMiningWrk.length) + return; + console.log('ERROR IN PROCESS: ' + err); + }); + Worker.on('close', function(code) { + console.log(`STOP PROCESS: ${Worker.Num} pid: ${Worker.pid} code: ${code}`) + for (var i = 0; i < ArrMiningWrk.length; i++) { + if (ArrMiningWrk[i].pid === Worker.pid) { + console.log("Delete wrk from arr - pid:" + Worker.pid); + ArrMiningWrk.splice(i, 1); + } + } + }); + } +} + +console.log("START MINER PROCESS COUNT: " + thread + " Memory: " + ProcessMemorySize / 1024 / 1024 + " Mb for each process"); + +setInterval(() => { + if (!ArrMiningWrk.length) { + console.log(`ArrMiningWrk.length == ${ArrMiningWrk.length} Starting all node...`) + RunProcess(); + } +}, 1000) diff --git a/tsconfig.json b/tsconfig.json index 18feec3..f087621 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,9 @@ "compilerOptions": { "outDir": "dist", "allowJs": true, - "target": "es5" + "target": "es5", + "emitDecoratorMetadata": true, + "experimentalDecorators": true }, "include": [ "./src/**/*",