/* * @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 = "TX"; import * as crypto from 'crypto'; require("../core/constant"); global.DATA_PATH = global.GetNormalPathString(global.DATA_PATH); global.CODE_PATH = global.GetNormalPathString(global.CODE_PATH); require("../core/library"); global.READ_ONLY_DB = 0; var LastAlive = Date.now(); setTimeout(function() { setInterval(CheckAlive, 1000); }, 20000); setInterval(global.PrepareStatEverySecond, 1000); if (process.send) { setInterval(function() { process.send({ cmd: "Alive" }); }, 1000); process.send({ cmd: "online", message: "OK" }); global.ToLogClient = function(Str, StrKey, bFinal) { process.send({ cmd: "ToLogClient", Str: "" + Str, StrKey: StrKey, bFinal: bFinal }); }; } process.on('message', function(msg) { LastAlive = Date.now(); switch (msg.cmd) { case "ALive": break; case "Exit": process.exit(0); break; case "call": var Err = 0; var Ret; try { Ret = global[msg.Name](msg.Params); } catch (e) { Err = 1; Ret = "" + e; } if (msg.id) process.send({ cmd: "retcall", id: msg.id, Err: Err, Params: Ret }); break; case "FindTX": global.TreeFindTX.SaveValue(msg.TX, msg); break; case "SetSmartEvent": global.TreeFindTX.SaveValue("Smart:" + msg.Smart, 1); break; case "Eval": global.EvalCode(msg.Code); break; default: break; } }); global.SetStatMode = function(Val) { global.STAT_MODE = Val; return global.STAT_MODE; }; function CheckAlive() { if (global.NOALIVE) return; var Delta = Date.now() - LastAlive; if (Delta > 100 * 1000) { global.ToLog("TX-PROCESS: ALIVE TIMEOUT Stop and exit: " + Delta); process.exit(0); return; } }; process.on('uncaughtException', function(err) { global.ToError(err.stack); global.ToLog(err.stack); global.TO_ERROR_LOG("TX-PROCESS", 777, err); global.ToLog("-----------------TX-PROCESS EXIT------------------"); process.exit(); }); process.on('error' as any, function(err: TeraError) { global.ToError("TX-PROCESS:\n" + err.stack); global.ToLog(err.stack); }); global.HTTP_PORT_NUMBER = 0; var CServerDB = require("../core/transaction-validator"); var KeyPair = crypto.createECDH('secp256k1'); KeyPair.setPrivateKey(Buffer.from([77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77])); global.SERVER = new CServerDB(KeyPair, undefined, undefined, false, true); global.TreeFindTX = new global.STreeBuffer(30 * 1000, global.CompareItemHashSimple, "string"); setInterval(function() { if (global.SERVER) { global.SERVER.Close(); } DoTXProcess(); }, 10); var BlockTree = new global.STreeBuffer(30 * 1000, global.CompareItemHashSimple, "number"); global.bShowDetail = 0; var StopTxProcess = 0; var MinimalValidBlock = 0; var LastBlockNum = undefined; function DoTXProcess() { if (StopTxProcess) return; if (LastBlockNum === undefined) InitTXProcess(); var BlockMin = FindMinimal(); if (!BlockMin) { if (global.bShowDetail) global.ToLog("!BlockMin"); return; } var StartTime = Date.now(); if (global.bShowDetail) global.ToLog("BlockMin: " + BlockMin.BlockNum + " LastBlockNum=" + LastBlockNum); // var CountTX = 0; for (var Num = BlockMin.BlockNum; Num < BlockMin.BlockNum + 200; Num++) { var EndTime = Date.now(); var Delta = EndTime - StartTime; if (Delta >= 1000) break; var Block = global.SERVER.ReadBlockDB(Num); if (!Block) { if (global.bShowDetail) global.ToLog("!Block"); break; } if (!IsValidSumHash(Block)) { break; } var Item = BlockTree.LoadValue(Block.BlockNum, 1); if (Item && global.CompareArr(Item.SumHash, Block.SumHash) === 0) { if (global.bShowDetail) global.ToLog("WAS CALC: " + Num + " SumHash: " + global.GetHexFromArr(Block.SumHash).substr(0, 12)); continue; } if (Num > 0) { var Block0 = global.SERVER.ReadBlockDB(Num - 1); if (Block0) { var Item0 = BlockTree.LoadValue(Block0.BlockNum, 1); if (Item0 && global.CompareArr(Item0.SumHash, Block0.SumHash) !== 0) { break; } } } global.SERVER.BlockProcessTX(Block); if (Num % 100000 === 0) global.ToLog("CALC: " + Num); // CountTX++; if (global.bShowDetail) global.ToLog(" CALC: " + Num + " SumHash: " + global.GetHexFromArr(Block.SumHash).substr(0, 12)); BlockTree.SaveValue(Block.BlockNum, { BlockNum: Block.BlockNum, SumHash: Block.SumHash }); LastBlockNum = Block.BlockNum; } }; function FindMinimal() { var MaxNumBlockDB = global.SERVER.GetMaxNumBlockDB(); if (MaxNumBlockDB && MaxNumBlockDB < LastBlockNum) { if (global.bShowDetail) global.ToLog("MaxNumBlockDB 0) { RewriteAllTransactions(); } Block = global.SERVER.ReadBlockHeaderDB(MinimalValidBlock); return Block; }; function IsValidSumHash(Block) { if (Block.BlockNum <= MinimalValidBlock + global.BLOCK_PROCESSING_LENGTH2) return 1; if (Block.BlockNum < 16) return 1; if (global.IsZeroArr(Block.SumHash)) return 0; var PrevBlock = global.SERVER.ReadBlockHeaderDB(Block.BlockNum - 1); if (!PrevBlock) return 0; var SumHash2 = global.shaarr2(PrevBlock.SumHash, Block.Hash); if (global.CompareArr(SumHash2, Block.SumHash) === 0) return 1; return 0; }; function InitTXProcess() { var StateTX = global.DApps.Accounts.DBStateTX.Read(0); if (!StateTX) { LastBlockNum = 0; var MaxNum = global.DApps.Accounts.DBAccountsHash.GetMaxNum(); if (MaxNum > 0) { var Item = global.DApps.Accounts.DBAccountsHash.Read(MaxNum); if (Item) { LastBlockNum = Item.BlockNum; } } global.ToLog("DETECT NEW VER on BlockNum=" + LastBlockNum, 2); global.DApps.Accounts.DBStateTX.Write({ Num: 0, BlockNum: LastBlockNum, BlockNumMin: MinimalValidBlock }); } StateTX = global.DApps.Accounts.DBStateTX.Read(0); LastBlockNum = StateTX.BlockNum; MinimalValidBlock = StateTX.BlockNumMin; LastBlockNum = global.PERIOD_ACCOUNT_HASH * Math.trunc(LastBlockNum / global.PERIOD_ACCOUNT_HASH); if (LastBlockNum > 100) { LastBlockNum = 1 + LastBlockNum - 100; } global.DApps.Accounts.CalcMerkleTree(1); if (LastBlockNum <= 0) RewriteAllTransactions(); else global.ToLog("Start NUM = " + LastBlockNum, 2); }; global.ClearDataBase = ClearDataBase; function ClearDataBase() { MinimalValidBlock = 0; for (var key in global.DApps) { global.DApps[key].ClearDataBase(); } LastBlockNum = 0; BlockTree.Clear(); }; global.RewriteAllTransactions = RewriteAllTransactions; function RewriteAllTransactions() { if (MinimalValidBlock > 0) { global.ToLog("*************Cant run RewriteAllTransactions, MinimalValidBlock:" + MinimalValidBlock, 2); return; } global.ToLog("*************RewriteAllTransactions"); for (var key in global.DApps) { global.DApps[key].ClearDataBase(); } LastBlockNum = 0; BlockTree.Clear(); global.ToLog("Start num = " + LastBlockNum, 2); }; global.ReWriteDAppTransactions = ReWriteDAppTransactions; function ReWriteDAppTransactions(Params) { var StartNum = Params.StartNum; var EndNum = Params.EndNum; global.ToLog("ReWriteDAppTransactions: " + StartNum + " - " + EndNum); BlockTree.Clear(); if (StartNum < LastBlockNum) LastBlockNum = StartNum; global.ToLog("Start num = " + LastBlockNum, 2); }; function TXPrepareLoadRest(BlockNum) { StopTxProcess = 1; MinimalValidBlock = BlockNum; global.ToLog("*************TXPrepareLoadRest:" + BlockNum, 2); for (var key in global.DApps) { global.DApps[key].ClearDataBase(); } LastBlockNum = BlockNum; BlockTree.Clear(); global.DApps.Accounts.DBStateTX.Write({ Num: 0, BlockNum: LastBlockNum, BlockNumMin: LastBlockNum }); }; global.TXPrepareLoadRest = TXPrepareLoadRest; function TXWriteAccArr(Params) { var WorkStruct = {}; var WorkFormat = global.DApps.Accounts.FORMAT_ACCOUNT_ROW; global.ToLog("Write accounts: " + Params.StartNum + "-" + Params.Arr.length, 2); for (var i = 0; i < Params.Arr.length; i++) { var Data = global.BufLib.GetObjectFromBuffer(Params.Arr[i], WorkFormat, WorkStruct); Data.Num = Params.StartNum + i; global.DApps.Accounts._DBStateWrite(Data, MinimalValidBlock); } }; global.TXWriteAccArr = TXWriteAccArr; function TXWriteSmartArr(Params) { var WorkStruct = {}; var WorkFormat = global.DApps.Smart.FORMAT_ROW; global.ToLog("Write smarts: " + Params.StartNum + "-" + Params.Arr.length, 2); for (var i = 0; i < Params.Arr.length; i++) { var Data = global.BufLib.GetObjectFromBuffer(Params.Arr[i], WorkFormat, WorkStruct); Data.Num = Params.StartNum + i; global.DApps.Smart.DBSmart.Write(Data); } }; global.TXWriteSmartArr = TXWriteSmartArr; function TXWriteAccHash() { StopTxProcess = 0; global.ToLog("Start TXWriteAccHash: " + MinimalValidBlock, 2); for (var num = 0; true; num++) { var Item = global.DApps.Smart.DBSmart.Read(num); if (!Item) break; // var Body = global.BufLib.GetBufferFromObject(Item, global.DApps.Smart.FORMAT_ROW, 20000, {}); global.DApps.Smart.DBSmartWrite(Item); } global.DApps.Accounts.CalcMerkleTree(1); var Block = { BlockNum: MinimalValidBlock, SumHash: [] }; var MaxAccount = global.DApps.Accounts.GetMaxAccount(); var DataHash = global.DApps.Accounts.CalcHash(Block, MaxAccount); return DataHash; }; global.TXWriteAccHash = TXWriteAccHash; global.EvalCode = function(Code) { var Result; try { var ret = eval(Code); Result = JSON.stringify(ret, undefined, 4); } catch (e) { Result = "" + e; } return Result; };