tera/src/core/base.ts

428 lines
15 KiB
TypeScript

/*
* @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 "./library"
import "./crypto-library"
import "./terahashmining"
import { RBTree } from './library'
import * as crypto from 'crypto';
import * as os from 'os'
import CNode from "./node";
import { Comparator } from "bintrees";
import { SocketSendInfo } from "../interfaces/server";
global.glStopNode = false;
const MAX_TIME_NETWORK_TRANSPORT = 1 * 1000;
var GlSumUser: number;
var GlSumSys: number;
var GlSumIdle: number;
global.CountAllNode = 0;
export default class CCommon {
VirtualMode: any
KeyPair: crypto.ECDH
PubKeyType: string
addrArr: string[]
addrStr: string
HashDBArr: any
ServerSign: any[] | Buffer
MetaMap1: any
MetaMap2: any
CheckName: any
NodesArr: any[]
CurrentBlockNum: number
BlockNumDB: number
constructor(SetKeyPair: crypto.ECDH, RunIP: string, RunPort: number, UseRNDHeader: boolean, bVirtual: boolean) {
global.SERVER = this
this.VirtualMode = bVirtual
this.KeyPair = SetKeyPair
var PubKey: string[] = SetKeyPair.getPublicKey(undefined, 'compressed') as any;
this.PubKeyType = PubKey[0]
this.addrArr = PubKey.slice(1)
this.addrStr = global.GetHexFromArr(this.addrArr)
this.HashDBArr = global.shaarr2(this.KeyPair.getPrivateKey(), [0, 0, 0, 0, 0, 0, 0, 1])
this.ServerSign = []
}
SendF(Node: CNode, Info: SocketSendInfo, Length?: number) {
throw new Error('Unsupport Action...')
// defiend in server.ts
}
AddCheckErrCount(Node: CNode, Count: number, StrErr: string) {
throw new Error('Unsupport Action...')
// defiend in server.ts
}
GetActualNodes(): any {
throw new Error('Unsupport Action...')
// defiend in server.ts
}
ReadBlockHeaderDB(BlockNum: number): any {
throw new Error('Unsupport Action...')
// defiend in block-db.ts(CDB)
}
AddStatOnTimer() {
var CountAll = 0;
var CurTime = global.GetCurrentTime() - 0;
for (var i = 0; i < this.NodesArr.length; i++) {
var Item = this.NodesArr[i];
if (Item.LastTime && (CurTime - Item.LastTime) < global.NODES_DELTA_CALC_HOUR * 3600 * 1000)
CountAll++
else
if (Item.LastTimeGetNode && (CurTime - Item.LastTimeGetNode) < global.NODES_DELTA_CALC_HOUR * 3600 * 1000)
CountAll++
}
global.CountAllNode = CountAll
if (!global.STAT_MODE)
return;
var StateTX = global.DApps.Accounts.DBStateTX.Read(0);
if (StateTX) {
var Delta = this.CurrentBlockNum - StateTX.BlockNum;
global.ADD_TO_STAT("MAX:DELTA_TX", Delta)
}
var bHasCP = 0;
if (global.CHECK_POINT.BlockNum) {
var Block = this.ReadBlockHeaderDB(global.CHECK_POINT.BlockNum);
if (Block && global.CompareArr(global.CHECK_POINT.Hash, Block.Hash) === 0)
bHasCP = 1
}
var MinVer = global.MIN_VER_STAT;
if (MinVer === 0)
MinVer = global.UPDATE_CODE_VERSION_NUM
var BufMap = {}, BufMap2 = {};
var arr = this.GetActualNodes();
var Count = 0, CountHot = 0, CountHotOK = 0, CountActualOK = 0, SumDeltaHot = 0, SumDeltaActual = 0, CountCP = 0, CountLH = 0,
CountHash = 0, CountVer = 0, CountStop = 0;
var CountAutoCorrectTime = 0;
var SumAvgDeltaTime = 0;
for (var i = 0; i < arr.length; i++) {
var Node = arr[i];
if (!Node || Node.IsAddrList)
continue;
var INFO = Node.INFO;
if (!INFO)
INFO = {}
if (bHasCP && global.CHECK_POINT.BlockNum && INFO.CheckPointHashDB && global.CompareArr(global.CHECK_POINT.Hash, INFO.CheckPointHashDB) === 0) {
CountCP++
}
if (INFO.LoadHistoryMode)
CountLH++
if (Node.StopGetBlock)
CountStop++
Count++
SumAvgDeltaTime += Node.DeltaGlobTime
if (Node.VersionNum >= MinVer)
CountVer++
if (INFO && INFO.BlockNumDB && INFO.BlockNumDB <= this.BlockNumDB) {
var HashDB = ReadHashFromBufDB(BufMap2, INFO.BlockNumDB);
if (HashDB && global.CompareArr(HashDB, INFO.HashDB) === 0)
CountHash++
}
var StrChk = GetCheckAccHash(BufMap, INFO.AccountBlockNum, INFO.AccountsHash);
var Chck = 0;
if (StrChk.indexOf("=OK=") >= 0) {
Chck = 1
}
var DeltaTime = Node.DeltaTime;
if (!DeltaTime)
DeltaTime = 0
CountActualOK += Chck
SumDeltaActual += DeltaTime
if (Node.Hot) {
CountHot++
CountHotOK += Chck
SumDeltaHot += DeltaTime
}
if (INFO.AutoCorrectTime)
CountAutoCorrectTime++
}
global.ADD_TO_STAT("MAX:ALL_NODES", CountAll)
global.ADD_TO_STAT("MAX:CONNECTED_NODES", Count)
global.ADD_TO_STAT("MAX:HOT_NODES", CountHot)
global.ADD_TO_STAT("MAX:HOT_OK", CountHotOK)
global.ADD_TO_STAT("MAX:ACTUAL_OK", CountActualOK)
global.ADD_TO_STAT("MAX:CHECK_POINT_OK", CountCP)
global.ADD_TO_STAT("MAX:COUNTLH", CountLH)
global.ADD_TO_STAT("MAX:HASH_OK", CountHash)
global.ADD_TO_STAT("MAX:MIN_VERSION", CountVer)
global.ADD_TO_STAT("MAX:STOP_GET", CountStop)
global.ADD_TO_STAT("MAX:AUTOCORRECT", CountAutoCorrectTime)
global.ADD_TO_STAT("MAX:TIME_DELTA", global.DELTA_CURRENT_TIME)
if (!Count)
Count = 1
if (!CountHot)
CountHot = 1
if (Count >= 20) {
var SumDeltaAvg = 0;
var AvgGlobTime = SumAvgDeltaTime / Count;
for (var i = 0; i < arr.length; i++) {
var Node = arr[i];
if (!Node || Node.IsAddrList)
continue;
var Delta = AvgGlobTime - Node.DeltaGlobTime;
SumDeltaAvg += Delta * Delta
}
SumDeltaAvg = Math.sqrt(SumDeltaAvg / Count)
global.ADD_TO_STAT("MAX:DELTA_GLOB_TIME", 100 + AvgGlobTime)
global.ADD_TO_STAT("MAX:DISP_DELTA_GLOB_TIME", SumDeltaAvg)
arr.sort(function(a, b) {
return a.DeltaGlobTime - b.DeltaGlobTime;
})
var SumDeltaAvgM = 0;
var AvgGlobTimeM = arr[Math.trunc(arr.length / 2)].DeltaGlobTime;
var Length = arr.length;
var Start = Math.trunc(Length * 0.05);
var End = Math.trunc(Length * 0.95);
var NodesCount = 0;
for (var i = Start; i < End; i++) {
var Node = arr[i];
if (!Node || Node.IsAddrList)
continue;
NodesCount++
var Delta = AvgGlobTimeM - Node.DeltaGlobTime;
SumDeltaAvgM += Delta * Delta
}
if (!NodesCount)
NodesCount = 1
SumDeltaAvgM = Math.sqrt(SumDeltaAvgM / NodesCount)
global.ADD_TO_STAT("MAX:MEDIAN_GLOB_TIME", 100 + AvgGlobTimeM)
global.ADD_TO_STAT("MAX:DISP_MEDIAN_GLOB_TIME", SumDeltaAvgM)
}
global.ADD_TO_STAT("MAX:DELTA_TIME_HOT", SumDeltaHot / CountHot)
global.ADD_TO_STAT("MAX:DELTA_TIME_ACTUAL", SumDeltaActual / Count)
global.ADD_TO_STAT("MAX:MEMORY_USAGE", process.memoryUsage().heapTotal / 1024 / 1024)
global.ADD_TO_STAT("MAX:MEMORY_FREE", os.freemem() / 1024 / 1024)
var SumUser = 0;
var SumSys = 0;
var SumIdle = 0;
var cpus = os.cpus();
for (var i = 0; i < cpus.length; i++) {
var cpu = cpus[i];
SumUser += cpu.times.user
SumSys += cpu.times.sys + cpu.times.irq
SumIdle += cpu.times.idle
}
if (GlSumUser !== undefined) {
var maxsum = cpus.length * 1000;
global.ADD_TO_STAT("MAX:CPU_USER_MODE", Math.min(maxsum, SumUser - GlSumUser))
global.ADD_TO_STAT("MAX:CPU_SYS_MODE", Math.min(maxsum, SumSys - GlSumSys))
global.ADD_TO_STAT("MAX:CPU_IDLE_MODE", Math.min(maxsum, SumIdle - GlSumIdle))
global.ADD_TO_STAT("MAX:CPU", Math.min(maxsum, SumUser + SumSys - GlSumUser - GlSumSys))
}
GlSumUser = SumUser
GlSumSys = SumSys
GlSumIdle = SumIdle
}
GetNewMeta() {
return crypto.randomBytes(32);
}
};
// class SMemBuffer {
// MetaMap1: { [x: string]: any; }
// MetaMap2: { [x: string]: any; }
// CheckName: any
// constructor(MaxTime: number, CheckName: any) {
// this.MetaMap1 = {}
// this.MetaMap2 = {}
// this.CheckName = CheckName
// setInterval(this.ShiftMapDirect.bind(this), MaxTime)
// }
// GetStrKey(Arr: any) {
// if (typeof Arr === "number" || typeof Arr === "string") {
// return Arr;
// } else {
// return global.GetHexFromAddres(Arr);
// }
// throw "NOT RET!";
// }
// LoadValue(Arr: any, bStay: any) {
// if (!Arr)
// return undefined;
// var Key = this.GetStrKey(Arr);
// var Value = this.MetaMap1[Key];
// if (Value !== undefined) {
// if (!bStay)
// delete this.MetaMap1[Key]
// return Value;
// }
// Value = this.MetaMap2[Key]
// if (Value !== undefined) {
// if (!bStay)
// delete this.MetaMap2[Key]
// }
// return Value;
// }
// SaveValue(Arr, Value) {
// var Key = this.GetStrKey(Arr);
// if (Value !== undefined)
// this.MetaMap1[Key] = Value
// }
// ShiftMapDirect() {
// if (global.glStopNode)
// return;
// if (this.CheckName) {
// var Count = 0;
// for (var _ in this.MetaMap2) {
// Count++
// }
// if (Count) {
// global.ADD_TO_STAT(this.CheckName, 1, 1)
// }
// }
// this.MetaMap2 = this.MetaMap1
// this.MetaMap1 = {}
// }
// Clear() {
// this.MetaMap2 = {}
// this.MetaMap1 = {}
// }
// };
export class STreeBuffer {
KeyType: string
MetaTree1: RBTree<any>
MetaTree2: RBTree<any>
CheckName: string
constructor(MaxTime: number, CompareFunction?: Comparator<any>, KeyType?: string, CheckName?: undefined) {
this.KeyType = KeyType
this.MetaTree1 = new RBTree(CompareFunction)
this.MetaTree2 = new RBTree(CompareFunction)
this.CheckName = CheckName
setInterval(this.ShiftMapDirect.bind(this), MaxTime)
}
LoadValue(Hash: string, bStay: number) {
if (!Hash)
return undefined;
if (typeof Hash !== this.KeyType)
throw "MUST ONLY HASH ARRAY: " + Hash;
var element = this.MetaTree1.find({ hash: Hash });
if (element) {
if (!bStay)
this.MetaTree1.remove(element)
return element.value;
}
element = this.MetaTree2.find({ hash: Hash })
if (element) {
if (!bStay)
this.MetaTree2.remove(element)
return element.value;
}
return undefined;
}
SaveValue(Hash: string, Value: { BlockNum: any; Power?: any; SumHash?: any; }) {
if (typeof Hash !== this.KeyType)
throw "MUST ONLY TYPE=" + this.KeyType + " in " + Hash;
if (Value !== undefined) {
var element = this.MetaTree1.find({ hash: Hash });
if (element)
element.value = Value
else
this.MetaTree1.insert({ hash: Hash, value: Value })
}
}
ShiftMapDirect() {
if (this.CheckName && this.MetaTree2.size) {
global.ADD_TO_STAT(this.CheckName, this.MetaTree2.size, 1)
var it = this.MetaTree2.iterator(), Item;
while ((Item = it.next()) !== null) {
var Name = Item.value.Name;
global.ADD_TO_STAT(this.CheckName + ":" + Name, 1, 1)
}
}
this.MetaTree2.clear()
var empty_tree = this.MetaTree2;
this.MetaTree2 = this.MetaTree1
this.MetaTree1 = empty_tree
}
Clear() {
this.MetaTree1.clear()
this.MetaTree2.clear()
}
};
function ReadHashFromBufDB(Map: { [x: string]: any; }, BlockNum: number) {
var MyHash = Map[BlockNum];
if (!MyHash) {
var Block = global.SERVER.ReadBlockHeaderDB(BlockNum);
if (Block)
MyHash = Block.Hash;
else
MyHash = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
Map[BlockNum] = MyHash;
}
return MyHash;
};
function GetCheckAccHash(Map: { [x: string]: any; }, BlockNum: number, Hash: Buffer) {
var MyHash = Map[BlockNum];
if (!MyHash) {
MyHash = global.DApps.Accounts.GetHashOrUndefined(BlockNum);
Map[BlockNum] = MyHash;
}
if (MyHash) {
if (!Hash)
return "=ERR:NO=";
if (global.CompareArr(Hash, MyHash) !== 0)
return "=ERR:BAD=";
else
return "=OK=";
} else {
if (!Hash)
return "=OK=:NO";
else
return "=MY:NO=";
}
};
global.GetCheckAccHash = GetCheckAccHash;
global.ReadHashFromBufDB = ReadHashFromBufDB;
global.STreeBuffer = STreeBuffer;
global.TestCreateTr = TestCreateTr;
function TestCreateTr() {
const FORMAT_CREATE = "{\
Type:byte,\
Currency:uint,\
PubKey:arr33,\
Description:str40,\
Adviser:uint,\
Reserve:arr7,\
POWCreate:arr12,\
}";
var TR = {
Type: 100, Currency: 0, PubKey: [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0], Description: "Description", Adviser: 10,
};
var Body = global.BufLib.GetBufferFromObject(TR, FORMAT_CREATE, 1000, {});
var startTime = process.hrtime();
var StartData = Date.now();
var nonce = CreateHashBodyPOWInnerMinPower(Body, 1000, 17);
var Time = process.hrtime(startTime);
var power = global.GetPowPower(global.shaarr(Body));
var deltaTime = (Time[0] * 1000 + Time[1] / 1e6) / 1000;
var DeltaData = ((new Date() as any) - StartData) / 1000;
global.ToLog("power=" + power + " nonce=" + nonce + " TIME=" + deltaTime + " sec" + " DeltaData=" + DeltaData + " sec");
return { time1: deltaTime, time2: DeltaData };
};
function CreateHashBody(body: Buffer, Num: number, Nonce: number) {
body.writeUIntLE(Num, body.length - 12, 6);
body.writeUIntLE(Nonce, body.length - 6, 6);
return global.shaarr(body);
};
function CreateHashBodyPOWInnerMinPower(arr: Buffer, BlockNum: number, MinPow: number) {
var nonce = 0;
while (1) {
var arrhash = CreateHashBody(arr, BlockNum, nonce);
var power = global.GetPowPower(arrhash);
if (power >= MinPow) {
return nonce;
}
nonce++;
}
};