/* * @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 = "WEB"; const crypto = require('crypto'); const http = require('http'), net = require('net'), url = require('url'), fs = require('fs'), querystring = require('querystring'); global.MAX_STAT_PERIOD = 600; require("../core/constant"); global.MAX_STAT_PERIOD = 600; global.DATA_PATH = GetNormalPathString(global.DATA_PATH); global.CODE_PATH = GetNormalPathString(global.CODE_PATH); require("../core/library"); require("../core/geo"); require("./child-process"); global.READ_ONLY_DB = 1; global.MAX_STAT_PERIOD = 600; var HostNodeList = []; var AllNodeList = []; var NodeBlockChain = []; process.on('message', function (msg) { switch(msg.cmd) { case "Stat": ADD_TO_STAT(msg.Name, msg.Value); break; case "NodeList": HostNodeList = msg.Value; AllNodeList = msg.ValueAll; break; case "NodeBlockChain": NodeBlockChain = msg.Value; break; case "DappEvent": { AddDappEventToGlobalMap(msg.Data); break; } case "ToLogClient": { ToLogClient0(msg.Str, msg.StrKey, msg.bFinal); break; } case "RetFindTX": { if(msg.WebID) { var F = global.GlobalRunMap[msg.WebID]; if(F) { delete global.GlobalRunMap[msg.WebID]; F(msg.Result, msg.ResultStr); break; } } ArrLogClient.push({text:msg.ResultStr, key:msg.TX, final:msg.bFinal, }); break; } } }); var RedirectServer; var HostingServer; global.OnExit = function () { if(RedirectServer) RedirectServer.close(); if(HostingServer) HostingServer.close(); }; if(!global.HTTP_HOSTING_PORT) { ToLogTrace("global.HTTP_HOSTING_PORT=" + global.HTTP_HOSTING_PORT); OnExit(); process.exit(); } var CServerDB = require("../core/db/block-db"); 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.HTTP_PORT_NUMBER = 0; require("../core/html-server"); require("../core/transaction-validator"); global.STAT_MODE = 1; setInterval(PrepareStatEverySecond, 1000); var IndexName = "index.html"; if(global.HTTPS_HOSTING_DOMAIN && HTTP_HOSTING_PORT === 443) { var file_sert = GetDataPath("sertif.lst"); CheckCreateDir(GetDataPath("tmp")); var greenlock = require('greenlock').create({version:'draft-12', server:'https://acme-v02.api.letsencrypt.org/directory', configDir:GetDataPath('tmp'), }); var redir = require('redirect-https')(); RedirectServer = require('http').createServer(greenlock.middleware(redir)); RedirectServer.on('error', function (err) { ToError('RedirectServer: ' + err.code); }); RedirectServer.listen(80); var GetNewSert = 1; if(fs.existsSync(file_sert)) { var certs = LoadParams(file_sert, {}); var Delta = certs.expiresAt - Date.now(); if(Delta >= 10 * 24 * 3600 * 1000) { ToLog("USE EXIST SERT. ExpiresAt: " + new Date(certs.expiresAt)); GetNewSert = 0; var tlsOptions = {key:certs.privkey, cert:certs.cert + '\r\n' + certs.chain}; HostingServer = require('https').createServer(tlsOptions, MainHTTPFunction); RunListenServer(); } } if(GetNewSert) { ToLog("Start get new SERT", 0); var opts = {domains:[global.HTTPS_HOSTING_DOMAIN], email:'progr76@gmail.com', agreeTos:true, communityMember:true, }; greenlock.register(opts).then(function (certs) { SaveParams(file_sert, certs); var tlsOptions = {key:certs.privkey, cert:certs.cert + '\r\n' + certs.chain}; HostingServer = require('https').createServer(tlsOptions, MainHTTPFunction); RunListenServer(); }, function (err) { ToError(err); }); } } else { HostingServer = http.createServer(MainHTTPFunction); RunListenServer(); } function MainHTTPFunction(request,response) { if(!request.headers) return ; if(!request.socket || !request.socket.remoteAddress) return ; SetSafeResponce(response); var DataURL = url.parse(request.url); var Params = querystring.parse(DataURL.query); var Path = querystring.unescape(DataURL.pathname); ToLogWeb("Get Path:" + Path); if(global.STAT_MODE === 2) { ADD_TO_STAT("HTTP_ALL"); response.DetailStatName = ":" + Path; } var Type = request.method; if(Type === "POST") { let Response = response; let postData = ""; request.addListener("data", function (postDataChunk) { if(postData.length <= 12000 && postDataChunk.length <= 12000) postData += postDataChunk; else { var Str = "Error postDataChunk.length=" + postDataChunk.length; ToLog(Str, 0); Response.writeHead(405, {'Content-Type':'text/html'}); Response.end(Str); } }); request.addListener("end", function () { var Data; if(postData && postData.length) { try { Data = JSON.parse(postData); } catch(e) { Response.writeHead(405, {'Content-Type':'text/html'}); Response.end("Error data parsing"); } } DoCommandNew(request, response, Type, Path, Data); }); } else { DoCommandNew(request, response, Type, Path, Params); } }; var bWasRun = 0; var TimeToRerun = 3000; function RunListenServer() { HostingServer.on('error', function (err) { if(err.code === 'EADDRINUSE') { TimeToRerun = Math.floor(TimeToRerun * 1.1); if(TimeToRerun > 1000000 * 1000) return ; ToLog('Port ' + global.HTTP_HOSTING_PORT + ' in use, retrying...'); if(HostingServer.Server) HostingServer.Server.close(); if(!bWasRun) setTimeout(function () { if(!bWasRun) RunListenServer(); }, TimeToRerun); return ; } ToError("H##6"); ToError(err); }); ToLog("Prepare to run WEB-server on port: " + global.HTTP_HOSTING_PORT); HostingServer.listen(global.HTTP_HOSTING_PORT, LISTEN_IP, function () { if(!bWasRun) ToLog("Run WEB-server on " + LISTEN_IP + ":" + global.HTTP_HOSTING_PORT); bWasRun = 1; }); }; if(global.HTTP_START_PAGE) IndexName = global.HTTP_START_PAGE; else { var SiteFolder = GetNormalPathString("./SITE"); if(!fs.existsSync(SiteFolder)) { IndexName = "web-wallet.html"; } } var LangPathMap = {}; LangPathMap["ru"] = 1; LangPathMap["cn"] = 1; LangPathMap["de"] = 1; LangPathMap["blog"] = 1; LangPathMap["docs"] = 1; LangPathMap["game"] = 1; var WalletFileMap = {}; WalletFileMap["coinlib.js"] = 1; WalletFileMap["client.js"] = 1; WalletFileMap["diagram.js"] = 1; WalletFileMap["sha3.js"] = 1; WalletFileMap["terahashlib.js"] = 1; WalletFileMap["wallet-web.js"] = 1; WalletFileMap["wallet-lib.js"] = 1; WalletFileMap["crypto-client.js"] = 1; WalletFileMap["dapp-inner.js"] = 1; WalletFileMap["marked.js"] = 1; WalletFileMap["highlight.js"] = 1; WalletFileMap["highlight-js.js"] = 1; WalletFileMap["highlight-html.js"] = 1; WalletFileMap["codes.css"] = 1; WalletFileMap["sign-lib-min.js"] = 1; WalletFileMap["buttons.css"] = 1; WalletFileMap["style.css"] = 1; WalletFileMap["wallet.css"] = 1; WalletFileMap["history.html"] = 1; WalletFileMap["blockviewer.html"] = 1; WalletFileMap["web-wallet.html"] = 1; WalletFileMap["address_book.png"] = 1; WalletFileMap["mobile-wallet.html"] = 1; WalletFileMap["mobile-wallet.js"] = 1; WalletFileMap["mobile-wallet.css"] = 1; WalletFileMap["reload.svg"] = 1; WalletFileMap["T.svg"] = 1; WalletFileMap["B.svg"] = 1; WalletFileMap["blank.svg"] = 1; WalletFileMap["info.svg"] = 1; WalletFileMap["info.svg"] = 1; WalletFileMap["check.svg"] = 1; WalletFileMap["right-arrow.svg"] = 1; WalletFileMap["down-arrow.svg"] = 1; WalletFileMap["glass.svg"] = 1; WalletFileMap["up.png"] = 1; WalletFileMap["down.png"] = 1; WalletFileMap["dapp-edit.html"] = 1; WalletFileMap["TeraLogo.svg"] = 1; WalletFileMap["mobile-wallet.html"] = "web-wallet.html"; global.WebApi2 = {}; global.HostingCaller = {}; function DoCommandNew(request,response,Type,Path,Params) { if(Path.substring(0, 1) === "/") Path = Path.substring(1); var ArrPath = Path.split('/', 5); if(global.AddonCommand) { if(!global.AddonCommand(request, response, Type, Path, Params, ArrPath)) return ; } var Caller = HostingCaller; var Method = ArrPath[0]; var APIv2 = 0; if(ArrPath[0] === "api") { if(ArrPath[1] === "v2") { APIv2 = 1; if(!global.USE_HARD_API_V2) { response.writeHead(200, {'Content-Type':'text/plain', 'Access-Control-Allow-Origin':"*"}); response.end(JSON.stringify({result:0, text:"You must set const USE_HARD_API_V2:1"})); return ; } Caller = WebApi2; } Method = ArrPath[2]; } if(global.STAT_MODE === 2) { ADD_TO_STAT("HTTP:" + Method); response.DetailStatName = ":" + Method; } var F = Caller[Method]; if(F) { response.writeHead(200, {'Content-Type':'text/plain', 'Access-Control-Allow-Origin':"*"}); if(!global.USE_API_V1 && !APIv2) { response.end(JSON.stringify({result:0, text:"This node not use USE_API_V1"})); return ; } var Ret; try { Ret = F(Params, response, ArrPath); } catch(e) { Ret = {result:0, text:e.message, text2:e.stack}; } if(Ret === null) return ; try { var Str; if(typeof Ret === "object") Str = JSON.stringify(Ret); else Str = Ret; response.end(Str); } catch(e) { ToLog("ERR PATH:" + Path); ToLog(e); response.end(); } return ; } Method = Method.toLowerCase(); if(Method === "dapp" && ArrPath.length === 2) Method = "DappTemplateFile"; switch(Method) { case "index.html": response.writeHead(301, {"Location":'/'}); return response.end(); case "file": SendBlockFile(response, ArrPath[1], ArrPath[2]); break; case "DappTemplateFile": DappTemplateFile(response, ArrPath[1]); break; case "smart": DappSmartCodeFile(response, ArrPath[1]); break; case "client": DappClientCodeFile(response, ArrPath[1]); break; default: { var Name = ArrPath[ArrPath.length - 1]; if(typeof Name !== "string") Name = "ErrorPath"; else if(Name.indexOf("..") >= 0 || Name.indexOf("\\") >= 0 || Name.indexOf("/") >= 0) Name = "ErrorFilePath"; if(Name === "" || LangPathMap[Name]) Name = IndexName; if(Name.indexOf(".") < 0) Name += ".html"; var PrefixPath; if(Method === "files") { PrefixPath = "../FILES"; Name = ""; for(var i = 1; i < ArrPath.length; i++) if(ArrPath[i].indexOf("..") === - 1 && ArrPath[i].indexOf("\\") === - 1) Name += "/" + ArrPath[i]; Name = PrefixPath + Name; SendWebFile(response, Name, Path); return ; } else if(LangPathMap[Method]) { PrefixPath = "./SITE/" + Method; } else { var Name2 = WalletFileMap[Name]; if(!Name2) PrefixPath = "./SITE"; else { PrefixPath = "./HTML"; if(typeof Name2 === "string") Name = Name2; } } var type = Path.substr(Path.length - 3, 3); switch(type) { case ".js": Name = PrefixPath + "/JS/" + Name; break; case "css": Name = PrefixPath + "/CSS/" + Name; break; case "wav": case "mp3": Name = PrefixPath + "/SOUND/" + Name; break; case "svg": case "png": case "gif": case "jpg": case "ico": Name = PrefixPath + "/PIC/" + Name; break; case "pdf": case "zip": case "exe": case "msi": Name = PrefixPath + "/FILES/" + Name; break; default: Name = PrefixPath + "/" + Name; break; } SendWebFile(response, Name, "", 1); break; } } }; HostingCaller.GetCurrentInfo = function (Params) { if(typeof Params === "object" && Params.BlockChain == 1) { if(!global.USE_API_WALLET) return {result:0}; } var MaxNumBlockDB = SERVER.GetMaxNumBlockDB(); var Ret = {result:1, VersionNum:global.UPDATE_CODE_VERSION_NUM, NETWORK:global.NETWORK, MaxNumBlockDB:MaxNumBlockDB, CurBlockNum:GetCurrentBlockNumByTime(), MaxAccID:DApps.Accounts.GetMaxAccount(), MaxDappsID:DApps.Smart.GetMaxNum(), CurTime:Date.now(), DELTA_CURRENT_TIME:DELTA_CURRENT_TIME, MIN_POWER_POW_TR:MIN_POWER_POW_TR, FIRST_TIME_BLOCK:FIRST_TIME_BLOCK, CONSENSUS_PERIOD_TIME:CONSENSUS_PERIOD_TIME, NEW_SIGN_TIME:NEW_SIGN_TIME, PRICE_DAO:PRICE_DAO(MaxNumBlockDB), }; if(typeof Params === "object" && Params.Diagram == 1) { var arrNames = ["MAX:ALL_NODES", "MAX:HASH_RATE_B"]; Ret.arr = GET_STATDIAGRAMS(arrNames); } if(typeof Params === "object" && Params.BlockChain == 1) { Ret.BlockChain = NodeBlockChain; } if(typeof Params === "object" && Params.ArrLog == 1) { var ArrLog = []; for(var i = 0; i < ArrLogClient.length; i++) { var Item = ArrLogClient[i]; if(!Item.final) continue; ArrLog.push(Item); } Ret.ArrLog = ArrLog; } return Ret; }; var MaxCountViewRows = global.HTTP_MAX_COUNT_ROWS; HostingCaller.GetAccountList = function (Params) { if(typeof Params !== "object") return {result:0}; if(Params.CountNum > MaxCountViewRows) Params.CountNum = MaxCountViewRows; if(!Params.CountNum) Params.CountNum = 1; var arr = DApps.Accounts.GetRowsAccounts(ParseNum(Params.StartNum), ParseNum(Params.CountNum)); return {result:1, arr:arr}; }; HostingCaller.GetAccount = function (id) { id = ParseNum(id); var arr = DApps.Accounts.GetRowsAccounts(id, 1); return {Item:arr[0], result:1}; }; HostingCaller.GetBlockList = function (Params,response) { if(typeof Params !== "object") return {result:0}; Params.StartNum = ParseNum(Params.StartNum); Params.CountNum = ParseNum(Params.CountNum); if(Params.CountNum > MaxCountViewRows) Params.CountNum = MaxCountViewRows; if(!Params.CountNum) Params.CountNum = 1; return HTTPCaller.GetBlockList(Params, response); }; HostingCaller.GetTransactionList = function (Params,response) { Params.Param3 = Params.BlockNum; return HostingCaller.GetTransactionAll(Params, response); }; HostingCaller.GetTransactionAll = function (Params,response) { if(typeof Params !== "object") return {result:0}; Params.Param3 = ParseNum(Params.Param3); Params.StartNum = ParseNum(Params.StartNum); Params.CountNum = ParseNum(Params.CountNum); if(Params.CountNum > MaxCountViewRows) Params.CountNum = MaxCountViewRows; return HTTPCaller.GetTransactionAll(Params, response); }; HostingCaller.GetDappList = function (Params) { if(typeof Params !== "object") return {result:0}; if(Params.CountNum > MaxCountViewRows) Params.CountNum = MaxCountViewRows; if(!Params.CountNum) Params.CountNum = 1; var arr = DApps.Smart.GetRows(ParseNum(Params.StartNum), ParseNum(Params.CountNum), undefined, Params.Filter, 1); return {result:1, arr:arr}; }; HostingCaller.GetNodeList = function (Params) { var arr = []; var List; if(typeof Params === "object" && Params.All) List = AllNodeList; else List = HostNodeList; var MaxNodes = 20; var len = List.length; var UseRandom = 0; if(len > MaxNodes) { UseRandom = 1; len = MaxNodes; } var Geo = 0; if(typeof Params === "object" && Params.Geo) Geo = 1; var mapWasAdd = {}; for(var i = 0; i < len; i++) { var Item; if(UseRandom) { var num = random(List.length); Item = List[num]; if(mapWasAdd[Item.ip]) { continue; } mapWasAdd[Item.ip] = 1; } else { Item = List[i]; } var Value = {ip:Item.ip, port:Item.portweb, }; if(Geo) { if(!Item.Geo) SetGeoLocation(Item); Value.latitude = Item.latitude; Value.longitude = Item.longitude; Value.name = Item.name; Value.port = Item.port; } arr.push(Value); } var Result = {result:1, arr:arr, VersionNum:global.UPDATE_CODE_VERSION_NUM, NETWORK:global.NETWORK, }; return Result; }; var AccountKeyMap = {}; var LastMaxNum = 0; HostingCaller.GetAccountListByKey = function (Params,aaa,bbb,bRet) { if(typeof Params !== "object" || !Params.Key) return {result:0, arr:[]}; if(!global.USE_API_WALLET) return {result:0}; var Accounts = DApps.Accounts; for(var num = LastMaxNum; true; num++) { if(Accounts.IsHole(num)) continue; var Data = Accounts.ReadState(num); if(!Data) break; var StrKey = GetHexFromArr(Data.PubKey); Data.Next = AccountKeyMap[StrKey]; AccountKeyMap[StrKey] = Data; } LastMaxNum = num; var arr = []; var Item = AccountKeyMap[Params.Key]; while(Item) { var Data = Accounts.ReadState(Item.Num); if(!Data) continue; if(!Data.PubKeyStr) Data.PubKeyStr = GetHexFromArr(Data.PubKey); if(Data.Currency) Data.CurrencyObj = DApps.Smart.ReadSimple(Data.Currency); if(Data.Value.Smart) { Data.SmartObj = DApps.Smart.ReadSimple(Data.Value.Smart); try { Data.SmartState = BufLib.GetObjectFromBuffer(Data.Value.Data, Data.SmartObj.StateFormat, {}); if(typeof Data.SmartState === "object") Data.SmartState.Num = Item.Num; } catch(e) { Data.SmartState = {}; } } arr.unshift(Data); Item = Item.Next; if(arr.length >= global.HTTP_MAX_COUNT_ROWS) break; } var Ret = {result:1, arr:arr}; if(bRet) { return Ret; } var Context = GetUserContext(Params); var StrInfo = JSON.stringify(Ret); if(Params.AllData === "0") Params.AllData = 0; if(!Params.AllData && Context.PrevAccountList === StrInfo) { return {result:0, cache:1}; } Context.PrevAccountList = StrInfo; Context.NumAccountList++; return StrInfo; }; var CategoryMap = {}; var CategoryArr = []; var CategoryDappMaxNumWas = 0; HostingCaller.GetDappCategory = function (Params,response) { CheckDappCategoryMap(); return {result:1, arr:CategoryArr}; }; function CheckDappCategoryMap() { var MaxNumNow = DApps.Smart.GetMaxNum(); if(MaxNumNow !== CategoryDappMaxNumWas) { for(var Num = CategoryDappMaxNumWas; Num <= MaxNumNow; Num++) { var Item = DApps.Smart.ReadSimple(Num); for(var n = 1; n <= 3; n++) { var Name = "Category" + n; var Value = Item[Name]; if(Value) { var DappMap = CategoryMap[Value]; if(!DappMap) { DappMap = {}; CategoryMap[Value] = DappMap; CategoryArr.push(Value); } DappMap[Num] = 1; } } } CategoryDappMaxNumWas = MaxNumNow; } }; HostingCaller.SendTransactionHex = function (Params,response) { if(typeof Params !== "object" || !Params.Hex) return {result:0, text:"object requre"}; process.RunRPC("AddTransactionFromWeb", {HexValue:Params.Hex}, function (Err,text) { var Result = {result:!Err, text:text}; var Str = JSON.stringify(Result); response.end(Str); }); return null; }; HostingCaller.DappSmartHTMLFile = function (Params) { if(typeof Params !== "object") return {result:0}; return HTTPCaller.DappSmartHTMLFile(Params); }; HostingCaller.DappBlockFile = function (Params,responce) { if(typeof Params !== "object") return {result:0}; return HTTPCaller.DappBlockFile(Params, responce); }; HostingCaller.DappInfo = function (Params) { if(typeof Params !== "object") return {result:0}; var SmartNum = ParseNum(Params.Smart); process.send({cmd:"SetSmartEvent", Smart:SmartNum}); var Context = GetUserContext(Params); var Ret = HTTPCaller.DappInfo(Params, undefined, 1); Ret.PubKey = undefined; var StrInfo = JSON.stringify(Ret); if(!Params.AllData && Context.PrevDappInfo === StrInfo) { return {result:0, cache:1}; } Context.PrevDappInfo = StrInfo; Context.NumDappInfo++; Context.LastTime = Date.now(); Ret.NumDappInfo = Context.NumDappInfo; Ret.CurTime = Date.now(); Ret.CurBlockNum = GetCurrentBlockNumByTime(); Ret.BlockNumDB = SERVER.BlockNumDB; Ret.MaxAccID = DApps.Accounts.GetMaxAccount(); Ret.MaxDappsID = DApps.Smart.GetMaxNum(); return Ret; }; HostingCaller.DappWalletList = function (Params) { if(typeof Params !== "object") return {result:0}; var Ret = HostingCaller.GetAccountListByKey(Params, undefined, undefined, 1); var Smart = ParseNum(Params.Smart); var arr = []; for(var i = 0; i < Ret.arr.length; i++) { if(Params.AllAccounts || Ret.arr[i].Value.Smart === Smart) { arr.push(Ret.arr[i]); } } Ret.arr = arr; return Ret; }; HTTPCaller.DappWalletList = HostingCaller.DappWalletList; HostingCaller.DappAccountList = function (Params) { if(typeof Params !== "object") return {result:0}; if(Params.CountNum > MaxCountViewRows) Params.CountNum = MaxCountViewRows; if(!Params.CountNum) Params.CountNum = 1; var arr = DApps.Accounts.GetRowsAccounts(ParseNum(Params.StartNum), ParseNum(Params.CountNum), undefined, 1); return {arr:arr, result:1}; }; HostingCaller.DappSmartList = function (Params) { if(typeof Params !== "object") return {result:0}; if(Params.CountNum > MaxCountViewRows) Params.CountNum = MaxCountViewRows; if(!Params.CountNum) Params.CountNum = 1; var arr = DApps.Smart.GetRows(ParseNum(Params.StartNum), ParseNum(Params.CountNum), undefined, undefined, Params.GetAllData, Params.TokenGenerate); return {arr:arr, result:1}; }; HostingCaller.DappBlockList = function (Params,response) { if(typeof Params !== "object") return {result:0}; Params.StartNum = ParseNum(Params.StartNum); Params.CountNum = ParseNum(Params.CountNum); if(Params.CountNum > MaxCountViewRows) Params.CountNum = MaxCountViewRows; if(!Params.CountNum) Params.CountNum = 1; return HTTPCaller.DappBlockList(Params, response); }; HostingCaller.DappTransactionList = function (Params,response) { if(typeof Params !== "object") return {result:0}; Params.BlockNum = ParseNum(Params.BlockNum); Params.StartNum = ParseNum(Params.StartNum); Params.CountNum = ParseNum(Params.CountNum); if(Params.CountNum > MaxCountViewRows) Params.CountNum = MaxCountViewRows; if(!Params.CountNum) Params.CountNum = 1; return HTTPCaller.DappTransactionList(Params, response); }; HostingCaller.DappStaticCall = function (Params,response) { if(typeof Params !== "object") return {result:0}; return HTTPCaller.DappStaticCall(Params, response); }; HostingCaller.GetHistoryTransactions = function (Params) { if(typeof Params !== "object") return {result:0}; return HTTPCaller.GetHistoryTransactions(Params); }; HostingCaller.GetSupply = function (Params) { if(HTTPS_HOSTING_DOMAIN === "terafoundation.org") return "" + (1000000000 - 411 * 1000000); var Data = DApps.Accounts.ReadState(0); if(!Data) return ""; else { return "" + (global.TOTAL_SUPPLY_TERA - Data.Value.SumCOIN); } }; HostingCaller.GetTotalSupply = function (Params) { return "" + global.TOTAL_SUPPLY_TERA; }; setInterval(function () { if(SERVER) SERVER.Close(); DApps.Accounts.Close(); DApps.Smart.DBSmart.Close(); }, 500); setInterval(function () { var MaxNumBlockDB = SERVER.GetMaxNumBlockDB(); var HASHARATE_BLOCK_LENGTH = 10; var arr = SERVER.GetStatBlockchain("POWER_BLOCKCHAIN", HASHARATE_BLOCK_LENGTH); if(arr.length) { var SumPow = 0; var Count = 0; var Value = 0; for(var i = arr.length - HASHARATE_BLOCK_LENGTH; i < arr.length; i++) if(arr[i]) { Value = arr[i]; SumPow += Value; Count++; } if(!Count) Count = 1; var AvgPow = SumPow / Count; ADD_TO_STAT("MAX:HASH_RATE_B", AvgPow); } var Count = COUNT_BLOCK_PROOF + 16 - 1; if(MaxNumBlockDB > Count) { var StartNum = MaxNumBlockDB - Count; NodeBlockChain = SERVER.BlockChainToBuf(StartNum, StartNum, MaxNumBlockDB); } }, 700); require("./api-exchange.js"); try { require("../SITE/JS/web-addon.js"); } catch(e) { } global.LoadBlockFromNetwork = function (Params,F) { ToLog("RUN: LoadBlockFromNetwork:" + Params.BlockNum, 2); process.RunRPC("LoadBlockFromNetwork", {BlockNum:Params.BlockNum, F:1}, function (Err,Block) { ToLog("RETURN: LoadBlockFromNetwork: " + Params.BlockNum, 2); F(Err, Block); }); }; if(global.LOCAL_RUN) { setTimeout(function () { require("../UnitTest/new-tx.js"); }, 1000); }