/* * @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 */ "use strict"; import * as fs from 'fs' const FORMAT_EVAL_SEND = "{MaxBlockNum:uint,Code:str,Sign:arr64}"; module.exports = class CCode extends require("./base") { LastEvalCodeNum constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) { super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) if (!global.ADDRLIST_MODE && !this.VirtualMode) { setInterval(this.CheckLoadCodeTime.bind(this), 10 * 1000) } this.LastEvalCodeNum = 0 global.CheckCreateDir(global.GetDataPath("Update")) } CheckLoadCodeTime() { if (global.START_LOAD_CODE.StartLoadNode && global.START_LOAD_CODE.StartLoadVersionNum) { var Delta = (new Date() as any) - global.START_LOAD_CODE.StartLoadVersionNumTime; if (Delta > 20 * 1000) { global.ToError("Cannot load code version:" + global.START_LOAD_CODE.StartLoadVersionNum + " from node: " + global.START_LOAD_CODE.StartLoadNode.ip + ":" + global.START_LOAD_CODE.StartLoadNode.port) this.ClearLoadCode() } } } ClearLoadCode() { global.START_LOAD_CODE.StartLoad = undefined global.START_LOAD_CODE.StartLoadVersionNum = 0 global.START_LOAD_CODE.StartLoadVersionNumTime = 0 } StartLoadCode(Node, CodeVersion) { var VersionNum = CodeVersion.VersionNum; global.START_LOAD_CODE.StartLoad = CodeVersion global.START_LOAD_CODE.StartLoadNode = Node global.START_LOAD_CODE.StartLoadVersionNum = VersionNum global.START_LOAD_CODE.StartLoadVersionNumTime = new Date() var fname = global.GetDataPath("Update/wallet-" + VersionNum + ".zip"); if (fs.existsSync(fname)) { this.UseCode(VersionNum, false) return; } var Context = { "VersionNum": VersionNum }; this.SendF(Node, { "Method": "GETCODE", "Context": Context, "Data": VersionNum }) } static GETCODE_F() { return "uint"; } RETCODE(Info) { var VersionNum = Info.Context.VersionNum; if (!VersionNum || !global.START_LOAD_CODE.StartLoad) return; var fname = global.GetDataPath("Update/wallet-" + VersionNum + ".zip"); if (!fs.existsSync(fname)) { var Hash = global.shaarr(Info.Data); if (global.CompareArr(Hash, global.START_LOAD_CODE.StartLoad.Hash) === 0) { var file_handle = fs.openSync(fname, "w"); fs.writeSync(file_handle, Info.Data, 0, Info.Data.length) fs.closeSync(file_handle) this.UseCode(VersionNum, global.USE_AUTO_UPDATE) } else { global.ToError("Error check hash of version code :" + global.START_LOAD_CODE.StartLoadVersionNum + " from node: " + Info.Node.ip + ":" + Info.Node.port) this.ClearLoadCode() this.AddCheckErrCount(Info.Node, 1, "Error check hash of version code") } } } UseCode(VersionNum, bUpdate) { if (bUpdate) { UpdateCodeFiles(VersionNum) } if (global.global.START_LOAD_CODE.StartLoad) { global.CODE_VERSION = global.START_LOAD_CODE.StartLoad this.ClearLoadCode() } } SetNewCodeVersion(Data, PrivateKey) { var fname = global.GetDataPath("ToUpdate/wallet.zip"); if (fs.existsSync(fname)) { var fname2 = global.GetDataPath("Update/wallet-" + Data.VersionNum + ".zip"); if (fs.existsSync(fname2)) { fs.unlinkSync(fname2) } var data = fs.readFileSync(fname); var Hash = global.shaarr(data); var file_handle = fs.openSync(fname2, "w"); fs.writeSync(file_handle, data, 0, data.length) fs.closeSync(file_handle) var SignArr = arr2(Hash, GetArrFromValue(Data.VersionNum)); var Sign = secp256k1.sign(SHA3BUF(SignArr), PrivateKey).signature; global.CODE_VERSION = Data global.CODE_VERSION.Hash = Hash global.CODE_VERSION.Sign = Sign return "OK Set new code version=" + Data.VersionNum; } else { return "File not exist: " + fname; } } }; function UpdateCodeFiles(StartNum) { var fname = global.GetDataPath("Update"); if (!fs.existsSync(fname)) return 0; var arr = fs.readdirSync(fname); var arr2 = []; for (var i = 0; i < arr.length; i++) { if (arr[i].substr(0, 7) === "wallet-") { arr2.push(parseInt(arr[i].substr(7))); } } arr2.sort(function(a, b) { return a - b; }); for (var i = 0; i < arr2.length; i++) { var Num = arr2[i]; var Name = "wallet-" + Num + ".zip"; var Path = fname + "/" + Name; global.ToLog("Check file:" + Name); if (fs.existsSync(Path)) { if (StartNum === Num) { global.ToLog("UnpackCodeFile:" + Name); UnpackCodeFile(Path); if (StartNum % 2 === 0) { global.RestartNode(1); } else { } return 1; } else { global.ToLog("Delete old file update:" + Name); fs.unlinkSync(Path); } } } return 0; }; global.UnpackCodeFile = UnpackCodeFile; function UnpackCodeFile(fname) { var data = fs.readFileSync(fname); var reader = ZIP.Reader(data); reader.forEach(function(entry) { var Name = entry.getName(); var Path = GetCodePath(Name); if (entry.isFile()) { var buf = entry.getData(); global.CheckCreateDir(Path, true, true); var file_handle = fs.openSync(Path, "w"); fs.writeSync(file_handle, buf, 0, buf.length); fs.closeSync(file_handle); } else { } }); reader.close(); }; global.RestartNode = function RestartNode(bForce) { global.NeedRestart = 1; setTimeout(DoExit, 5000); if (global.nw || global.NWMODE) { } else { StopChildProcess(); global.ToLog("********************************** FORCE RESTART!!!"); return; } if (this.ActualNodes) { var it = this.ActualNodes.iterator(), Node; while ((Node = it.next()) !== null) { if (Node.Socket) CloseSocket(Node.Socket, "Restart"); } } this.StopServer(); this.StopNode(); StopChildProcess(); global.ToLog("****************************************** RESTART!!!"); global.ToLog("EXIT 1"); }; function DoExit() { global.ToLog("EXIT 2"); if (global.nw || global.NWMODE) { global.ToLog("RESTART NW"); var StrRun = '"' + process.argv[0] + '" .\n'; StrRun += '"' + process.argv[0] + '" .\n'; SaveToFile("run-next.bat", StrRun); const child_process = require('child_process'); child_process.exec("run-next.bat", { shell: true }); } global.ToLog("EXIT 3"); process.exit(0); };