/* * @project: TERA * @version: Development (beta) * @license: MIT (not for evil) * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] * Web: https://terafoundation.org * Twitter: https://twitter.com/terafoundation * Telegram: https://t.me/terafoundation */ global.PROCESS_NAME = "MAIN"; import '../core/constant' import * as fs from 'fs' import * as os from 'os' import * as crypto from 'crypto'; global.START_SERVER = 1; 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 { secp256k1 } from '../core/library' global.ToLog(os.platform() + " (" + os.arch() + ") " + os.release()); var VerArr = process.versions.node.split('.'); global.ToLog("nodejs: " + process.versions.node); if ((VerArr[0] as any as number) < 8) { global.ToError("Error version of NodeJS=" + VerArr[0] + " Pls, download new version from www.nodejs.org and update it. The minimum version must be 8"); process.exit(); } import CServer from '../core/server' const DEF_PERIOD_SIGN_LIB = 500; setTimeout(function() { TestSignLib(DEF_PERIOD_SIGN_LIB); }, 4000); global.glCurNumFindArr = 0; global.ArrReconnect = []; global.ArrConnect = []; var FindList = [ { "ip": "60.12.241.181", "port": 30002 }, { "ip": "60.12.241.181", "port": 30003 }, { "ip": "60.12.241.181", "port": 30004 }, { "ip": "60.12.241.181", "port": 30005 }, { "ip": "60.12.241.181", "port": 30006 }, { "ip": "60.12.241.181", "port": 30007 }, { "ip": "60.12.241.181", "port": 30008 }, { "ip": "60.12.241.181", "port": 30009 }, { "ip": "60.12.241.181", "port": 30010 }, { "ip": "60.12.241.181", "port": 30011 }, { "ip": "60.12.241.181", "port": 30012 }, { "ip": "60.12.241.181", "port": 30013 }, { "ip": "60.12.241.181", "port": 30014 }, { "ip": "60.12.241.181", "port": 30016 }, { "ip": "60.12.241.181", "port": 30017 }, { "ip": "60.12.241.181", "port": 30018 }, ]; if (global.LOCAL_RUN) { FindList = [{ "ip": "127.0.0.1", "port": 50001 }, { "ip": "127.0.0.1", "port": 50002 }]; } else if (global.TEST_NETWORK) { FindList = [{ "ip": "149.154.70.158", "port": 40000 },]; } global.SERVER = undefined; global.NeedRestart = 0; process.on('uncaughtException' as any, function(err: TeraError) { if (global.PROCESS_NAME !== "MAIN") { process.send({ cmd: "log", message: err }); } global.ToError(err.stack); global.ToLog(err.stack); if (err.code === "ENOTFOUND" || err.code === "ECONNRESET" || err.code === "EPIPE") { } else { global.TO_ERROR_LOG("APP", 666, err); global.ToLog("-----------------EXIT------------------"); process.exit(); } }); process.on('error' as any, function(err: TeraError) { global.ToError(err.stack); global.ToLog(err.stack); }); var ArrChildProcess = []; var WebProcess: TeraProcess = { Name: "WEB PROCESS", idInterval: 0, idInterval1: 0, idInterval2: 0, LastAlive: Date.now(), Worker: undefined, Path: "./process/web-process.js", OnMessage: OnMessageWeb, PeriodAlive: 10 * 1000 }; global.WEB_PROCESS = WebProcess; if (global.HTTP_HOSTING_PORT && !global.NWMODE) { ArrChildProcess.push(WebProcess); WebProcess.idInterval1 = setInterval(function() { if (WebProcess.Worker && WebProcess.Worker.connected) { try { WebProcess.Worker.send({ cmd: "Stat", Name: "MAX:ALL_NODES", Value: global.CountAllNode }); } catch (e) { WebProcess.Worker = undefined; } } }, 500); WebProcess.idInterval2 = setInterval(function() { if (WebProcess.Worker && WebProcess.Worker.connected) { var arr = global.SERVER.GetDirectNodesArray(true, true).slice(1, 500); var arr2 = []; var CurTime = global.GetCurrentTime() - 0; for (var i = 0; i < global.SERVER.NodesArr.length; i++) { var Item = global.SERVER.NodesArr[i]; if (Item.LastTime && (CurTime - Item.LastTime) < global.NODES_DELTA_CALC_HOUR * 3600 * 1000) arr2.push({ ip: Item.ip, port: Item.port, webport: Item.webport }); else if (Item.LastTimeGetNode && (CurTime - Item.LastTimeGetNode) < global.NODES_DELTA_CALC_HOUR * 3600 * 1000) arr2.push({ ip: Item.ip, port: Item.port, webport: Item.webport }); } WebProcess.Worker.send({ cmd: "NodeList", Value: arr, ValueAll: arr2 }); } }, 5000); } function OnMessageWeb(msg) { switch (msg.cmd) { case "SetSmartEvent": { if (global.TX_PROCESS && global.TX_PROCESS.Worker) { global.TX_PROCESS.Worker.send(msg); } break; } } }; function AddTransactionFromWeb(Params) { var body = global.GetArrFromHex(Params.HexValue); if (global.TX_PROCESS && global.TX_PROCESS.Worker) { var StrHex = global.GetHexFromArr(global.sha3(body)); global.TX_PROCESS.Worker.send({ cmd: "FindTX", TX: StrHex, Web: 1, WebID: Params.WebID }); } var Res = global.SERVER.AddTransaction({ body: body }, 1); var text = global.AddTrMap[Res]; var final = false; if (Res <= 0 && Res !== - 3) final = true; global.ToLogClient("Send: " + text, global.GetHexFromArr(global.sha3(body)), final); return text; }; global.AddTransactionFromWeb = AddTransactionFromWeb; global.STATIC_PROCESS = { Name: "STATIC PROCESS", idInterval: 0, idInterval1: 0, idInterval2: 0, LastAlive: Date.now(), Worker: undefined, Path: "./process/static-process.js", OnMessage: OnMessageStatic, PeriodAlive: 50000 }; ArrChildProcess.push(global.STATIC_PROCESS); function OnMessageStatic(msg) { switch (msg.cmd) { case "Send": { var Node = global.SERVER.NodesMap[msg.addrStr]; if (Node) { msg.Data = msg.Data.data; global.SERVER.Send(Node, msg, 1); } break; } } }; global.TX_PROCESS = { Name: "TX PROCESS", idInterval: 0, idInterval1: 0, idInterval2: 0, LastAlive: Date.now(), Worker: undefined, Path: "./process/tx-process.js", OnMessage: OnMessageTX, PeriodAlive: 100 * 1000 }; ArrChildProcess.push(global.TX_PROCESS); function OnMessageTX(msg) { switch (msg.cmd) { case "DappEvent": { if (WebProcess && WebProcess.Worker) { WebProcess.Worker.send(msg); } global.AddDappEventToGlobalMap(msg.Data); break; } } }; function StartAllProcess(bClose) { for (var i = 0; i < ArrChildProcess.length; i++) { var Item = ArrChildProcess[i]; StartChildProcess(Item); } if (bClose) setInterval(function() { if (global.DApps && global.DApps.Accounts) { global.DApps.Accounts.Close(); global.DApps.Smart.DBSmart.Close(); } if (global.WALLET && global.DApps.DBHistory) global.DApps.DBHistory.Close(); }, 500); }; var GlobalRunID = 0; var GlobalRunMap = {}; function StartChildProcess(Item: TeraProcess) { let ITEM = Item; ITEM.idInterval = setInterval(function() { var Delta0 = Date.now() - ITEM.LastAlive; if (Delta0 >= 0) { var Delta = Date.now() - ITEM.LastAlive; if (ITEM.Worker && Delta > ITEM.PeriodAlive) { if (ITEM.Worker) { global.ToLog("KILL PROCESS " + ITEM.Name + ": " + ITEM.Worker.pid); try { process.kill(ITEM.Worker.pid, 'SIGKILL'); } catch (e) { global.ToLog("ERR KILL" + e); } ITEM.Worker = undefined; } } if (!ITEM.Worker) { ITEM.LastAlive = (Date.now()) + ITEM.PeriodAlive * 3; global.ToLog("STARTING " + ITEM.Name); ITEM.Worker = Fork(ITEM.Path, ["READONLYDB"]); ITEM.pid = ITEM.Worker.pid; global.ToLog("STARTED " + ITEM.Name + ":" + ITEM.pid); ITEM.Worker.on('message', function(msg) { if (ITEM.LastAlive < Date.now()) ITEM.LastAlive = Date.now(); switch (msg.cmd) { case "call": var Err = 0; var Ret; try { if (typeof msg.Params === "object" && msg.Params.F) { global[msg.Name](msg.Params, function(Err, Ret) { if (msg.id && ITEM.Worker) ITEM.Worker.send({ cmd: "retcall", id: msg.id, Err: Err, Params: Ret }); }); break; } else { Ret = global[msg.Name](msg.Params); } } catch (e) { Err = 1; Ret = "" + e; } if (msg.id && ITEM.Worker) ITEM.Worker.send({ cmd: "retcall", id: msg.id, Err: Err, Params: Ret }); break; case "retcall": var F = GlobalRunMap[msg.id]; if (F) { delete GlobalRunMap[msg.id]; F(msg.Err, msg.Params); } break; case "log": global.ToLog(msg.message); break; case "ToLogClient": if (WebProcess && WebProcess.Worker) { WebProcess.Worker.send(msg); } global.ToLogClient(msg.Str, msg.StrKey, msg.bFinal); break; case "RetFindTX": if (WebProcess && WebProcess.Worker) { WebProcess.Worker.send(msg); if (msg.Web) break; } global.ToLogClient(msg.ResultStr, msg.TX, msg.bFinal); break; case "online": if (ITEM.Worker) global.ToLog("RUNNING " + ITEM.Name + " : " + msg.message + " pid: " + ITEM.Worker.pid); break; case "WriteBodyResult": var Block = global.SERVER.ReadBlockDB(msg.BlockNum); if (Block) { Block.arrContentResult = msg.arrContentResult; global.SERVER.WriteBodyResultDB(Block); } break; default: if (ITEM.OnMessage) { ITEM.OnMessage(msg); } break; } }); ITEM.Worker.on('error', function(err) { }); ITEM.Worker.on('close', function(code) { global.ToError("CLOSE " + ITEM.Name); }); } } if (ITEM.Worker) { ITEM.Worker.send({ cmd: "Alive" }); } }, 500); ITEM.RunRPC = function(Name, Params, F) { if (!ITEM.Worker) return; if (F) { GlobalRunID++; try { ITEM.Worker.send({ cmd: "call", id: GlobalRunID, Name: Name, Params: Params }); GlobalRunMap[GlobalRunID] = F; } catch (e) { } } else { ITEM.Worker.send({ cmd: "call", id: 0, Name: Name, Params: Params }); } }; }; global.StopChildProcess = function() { for (var i = 0; i < ArrChildProcess.length; i++) { var Item = ArrChildProcess[i]; if (Item.idInterval) clearInterval(Item.idInterval); Item.idInterval = 0; if (Item.idInterval1) clearInterval(Item.idInterval1); Item.idInterval1 = 0; if (Item.idInterval2) clearInterval(Item.idInterval2); Item.idInterval2 = 0; if (Item.Worker && Item.Worker.connected) { Item.Worker.send({ cmd: "Exit" }); Item.Worker = undefined; } } RunStopPOWProcess("STOP"); }; require("../core/html-server"); RunServer(); setInterval(function run1() { DoConnectToNodes(global.ArrReconnect, "RECONNECT"); }, 200); setInterval(function run2() { DoGetNodes(); DoConnectToNodes(global.ArrConnect, "CONNECT"); }, 500); var StartCheckMining = 0; global.MiningPaused = 0; var ProcessMemorySize = 0; global.ArrMiningWrk = []; var BlockMining; if (global.ADDRLIST_MODE) { // @ts-ignore return; } function AllAlive() { for (var i = 0; i < global.ArrMiningWrk.length; i++) { global.ArrMiningWrk[i].send({ cmd: "Alive" }); } SendToClient({ cmd: "Alive" }) }; function ClearArrMining() { for (var i = 0; i < global.ArrMiningWrk.length; i++) { global.ArrMiningWrk[i].send({ cmd: "Exit" }); } global.ArrMiningWrk = []; }; function RunStopPOWProcess(Mode) { if (!global.GetCountMiningCPU() || global.GetCountMiningCPU() <= 0) return; if (!StartCheckMining) { StartCheckMining = 1; setInterval(RunStopPOWProcess, global.CHECK_RUN_MINING); setInterval(AllAlive, 1000); } if (global.NeedRestart) return; if (global.USE_MINING && global.MINING_START_TIME && global.MINING_PERIOD_TIME) { var Time = global.GetCurrentTime(); var TimeCur = Time.getUTCHours() * 3600 + Time.getUTCMinutes() * 60 + Time.getUTCSeconds(); var StartTime = global.GetSecFromStrTime(global.MINING_START_TIME); var RunPeriod = global.GetSecFromStrTime(global.MINING_PERIOD_TIME); var TimeEnd = StartTime + RunPeriod; global.MiningPaused = 1; if (TimeCur >= StartTime && TimeCur <= TimeEnd) { global.MiningPaused = 0; } else { StartTime -= 24 * 3600; TimeEnd -= 24 * 3600; if (TimeCur >= StartTime && TimeCur <= TimeEnd) { global.MiningPaused = 0; } } if (global.ArrMiningWrk.length && global.MiningPaused) { global.ToLog("------------ MINING MUST STOP ON TIME"); ClearArrMining(); return; } else if (!global.ArrMiningWrk.length && !global.MiningPaused) { global.ToLog("*********** MINING MUST START ON TIME"); } else { return; } } else { global.MiningPaused = 0; } if (!global.USE_MINING || Mode === "STOP") { ClearArrMining(); return; } if (global.USE_MINING && global.ArrMiningWrk.length) return; if (global.SERVER.LoadHistoryMode) return; if (global.GENERATE_BLOCK_ACCOUNT < 8) return; var PathMiner = global.GetCodePath("../miner.js"); if (!fs.existsSync(PathMiner)) PathMiner = "./process/pow-process.js"; if (global.ArrMiningWrk.length >= global.GetCountMiningCPU()) return; if (global.GrayConnect()) { global.ToLog("CANNOT START MINER IN NOT DIRECT IP MODE"); return; } var Memory; if (global.SIZE_MINING_MEMORY) Memory = global.SIZE_MINING_MEMORY; else { Memory = os.freemem() - (512 + global.GetCountMiningCPU() * 100) * 1024 * 1014; if (Memory < 0) { global.ToLog("Not enough memory to start processes."); return; } } ProcessMemorySize = Math.trunc(Memory / global.GetCountMiningCPU()); global.ToLog("START MINER PROCESS COUNT: " + global.GetCountMiningCPU() + " Memory: " + ProcessMemorySize / 1024 / 1024 + " Mb for each process"); for (var R = 0; R < global.GetCountMiningCPU(); R++) { let Worker = Fork(PathMiner); global.ArrMiningWrk.push(Worker); Worker.Num = global.ArrMiningWrk.length; Worker.on('message', function(msg) { if (msg.cmd === "log") { global.ToLog(msg.message); } else { if (msg.cmd === "online") { Worker.bOnline = true; global.ToLog("RUNNING PROCESS:" + Worker.Num + ":" + msg.message); } else { if (msg.cmd === "POW") { global.SERVER.MiningProcess(msg); } else { if (msg.cmd === "HASHRATE") { global.ADD_HASH_RATE(msg.CountNonce); } } } } }); Worker.on('error', function(err) { if (!global.ArrMiningWrk.length) return; global.ToError('ERROR IN PROCESS: ' + err); }); Worker.on('close', function(code) { global.ToLog("STOP PROCESS: " + Worker.Num + " pid:" + Worker.pid); for (var i = 0; i < global.ArrMiningWrk.length; i++) { if (global.ArrMiningWrk[i].pid === Worker.pid) { global.ToLog("Delete wrk from arr - pid:" + Worker.pid); global.ArrMiningWrk.splice(i, 1); } } }); } }; 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()) return; BlockMining = Block; for (var i = 0; i < global.ArrMiningWrk.length; i++) { var CurWorker = global.ArrMiningWrk[i]; if (!CurWorker.bOnline) continue; CurWorker.send({ 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(), Num: CurWorker.Num, RunPeriod: global.POWRunPeriod, RunCount: global.POW_RUN_COUNT, Percent: global.POW_MAX_PERCENT, CountMiningCPU: global.GetCountMiningCPU(), ProcessMemorySize: ProcessMemorySize, }); } }; global.SetCalcPOW = SetCalcPOW; global.RunStopPOWProcess = RunStopPOWProcess; function DoGetNodes() { if (!global.SERVER) return; if (!global.GrayConnect() && global.SERVER.CanSend < 2) return; if (!global.SERVER.NodesArrUnSort || !global.SERVER.NodesArrUnSort.length) return; var Num = global.glCurNumFindArr % global.SERVER.NodesArrUnSort.length; var Node = global.SERVER.NodesArrUnSort[Num]; if (Num === 0) global.glCurNumFindArr = 0; global.glCurNumFindArr++; if (Node.Delete) return; if (global.SERVER.NodeInBan(Node)) return; if (global.SERVER.BusyLevel && Node.BlockProcessCount <= global.SERVER.BusyLevel) return; if (global.GetSocketStatus(Node.Socket) === 100) { global.SERVER.StartGetNodes(Node); } }; function DoConnectToNodes(Arr, Mode) { if (!global.SERVER) return; if (!global.GrayConnect() && global.SERVER.CanSend < 2) { return; } if (global.GrayConnect() && global.SERVER.ActualNodes.size > global.GetGrayServerConnections()) return; if (Arr.length) { var MinProcessCount = global.SERVER.BusyLevel - 1; for (var i = 0; i < Arr.length; i++) { var Node = Arr[i]; if (Node.BlockProcessCount > MinProcessCount) { Arr.splice(i, 1); if (Mode === "CONNECT") { Node.WasAddToConnect = undefined; global.SERVER.StartConnectTry(Node); } else if (Mode === "RECONNECT") { Node.WasAddToReconnect = undefined; Node.CreateConnect(); } break; } } } }; var idRunOnce; function RunServer() { idRunOnce = setInterval(RunOnce, 1000); global.ToLog("NETWORK: " + global.GetNetworkName()); global.ToLog("VERSION: " + global.DEF_VERSION); if (global.NET_WORK_MODE) { global.START_IP = global.NET_WORK_MODE.ip; global.START_PORT_NUMBER = global.NET_WORK_MODE.port; } var KeyPair = crypto.createECDH('secp256k1'); if (!global.SERVER_PRIVATE_KEY_HEX || global.NEW_SERVER_PRIVATE_KEY) { while (true) { var Arr = crypto.randomBytes(32); KeyPair.setPrivateKey(Buffer.from(Arr)); var Arr2: any = KeyPair.getPublicKey('' as any, 'compressed'); if (Arr2[0] === 2) break; } global.SERVER_PRIVATE_KEY_HEX = global.GetHexFromArr(Arr); global.SAVE_CONST(true); } var ServerPrivKey = global.GetArrFromHex(global.SERVER_PRIVATE_KEY_HEX); if (global.USE_NET_FOR_SERVER_ADDRES) { const os = require('os'); var map = os.networkInterfaces(); main: for (var key in map) { var arr = map[key]; for (var i = 0; i < arr.length; i++) { var item = arr[i]; if (!item.internal && item.mac !== "00:00:00:00:00:00") { ServerPrivKey = global.sha3(global.SERVER_PRIVATE_KEY_HEX + ":" + item.mac + ":" + global.START_PORT_NUMBER); break main; } } } } KeyPair.setPrivateKey(Buffer.from(ServerPrivKey)); new CServer(KeyPair, global.START_IP, global.START_PORT_NUMBER, false, false); DoStartFindList(); }; function DoStartFindList() { var keyThisServer = global.SERVER.ip + ":" + global.SERVER.port; for (var n = 0; n < FindList.length; n++) { var item = FindList[n]; if (!item.ip) continue; var key = item.ip + ":" + item.port; if (keyThisServer === key) continue; var Node = global.SERVER.GetNewNode(item.ip, item.port); Node.StartFindList = 1; } }; function RunOnce() { if (global.SERVER && global.SERVER.CheckOnStartComplete) { clearInterval(idRunOnce); 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); global.ToLog("SET RESTART NODE AFTER: " + Period + " sec"); setInterval(function() { global.RestartNode(); }, Period * 1000); } setTimeout(function() { global.RunStopPOWProcess(); }, 10000); } }; var glPortDebug = 49800; import { fork } from 'child_process' 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"); glPortDebug++; var execArgv = []; var Worker = fork(Path, ArrArgs, { execArgv: execArgv }); return Worker as any; }; global.SpeedSignLib = 0; global.TestSignLib = TestSignLib; function TestSignLib(MaxTime) { if (!MaxTime) MaxTime = DEF_PERIOD_SIGN_LIB; var hash = Buffer.from(global.GetArrFromHex("A6B0914953F515F4686B2BA921B8FAC66EE6A6D3E317B43E981EBBA52393BFC6")); var PubKey = Buffer.from(global.GetArrFromHex("026A04AB98D9E4774AD806E302DDDEB63BEA16B5CB5F223EE77478E861BB583EB3")); var Sign = Buffer.from(global.GetArrFromHex("5D5382C65E4C1E8D412D5F30F87B8F72F371E9E4FC170761BCE583A961CF44966F92B38D402BC1CBCB7567335051A321B93F4E32112129AED4AB602E093A1187")); var startTime = process.hrtime(); var deltaTime = 1; for (var Num = 0; Num < 1000; Num++) { var Result = secp256k1.verify(hash, Sign, PubKey); if (!Result) { global.ToError("Error test sign"); process.exit(0); } var Time = process.hrtime(startTime); deltaTime = Time[0] * 1000 + Time[1] / 1e6; if (deltaTime > MaxTime) { global.ToLog("*************** WARNING: VERY SLOW LIBRARY: secp256k1 ***************"); global.ToLog("You can only process: " + Num + " transactions"); global.ToLog("Install all dependent packages, see detail: https://www.npmjs.com/package/secp256k1"); global.SpeedSignLib = Num; return 0; } } global.SpeedSignLib = Math.floor(Num * MaxTime / deltaTime); global.ToLog("TestSignLib: " + global.SpeedSignLib + " per sec"); return 1; };