update code
This commit is contained in:
440
Source/core/base.js
Normal file
440
Source/core/base.js
Normal file
@@ -0,0 +1,440 @@
|
||||
/*
|
||||
* @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";
|
||||
require("./library.js");
|
||||
require("./crypto-library");
|
||||
require("./terahashmining");
|
||||
const crypto = require('crypto');
|
||||
const os = require('os');
|
||||
global.glStopNode = false;
|
||||
const MAX_TIME_NETWORK_TRANSPORT = 1 * 1000;
|
||||
var GlSumUser;
|
||||
var GlSumSys;
|
||||
var GlSumIdle;
|
||||
global.CountAllNode = 0;
|
||||
module.exports = class CCommon
|
||||
{
|
||||
constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual)
|
||||
{
|
||||
global.SERVER = this
|
||||
this.VirtualMode = bVirtual
|
||||
this.KeyPair = SetKeyPair
|
||||
var PubKey = SetKeyPair.getPublicKey('', 'compressed');
|
||||
this.PubKeyType = PubKey[0]
|
||||
this.addrArr = PubKey.slice(1)
|
||||
this.addrStr = GetHexFromArr(this.addrArr)
|
||||
this.HashDBArr = shaarr2(this.KeyPair.getPrivateKey(), [0, 0, 0, 0, 0, 0, 0, 1])
|
||||
this.ServerSign = []
|
||||
}
|
||||
AddStatOnTimer()
|
||||
{
|
||||
var CountAll = 0;
|
||||
var CurTime = GetCurrentTime() - 0;
|
||||
for(var i = 0; i < this.NodesArr.length; i++)
|
||||
{
|
||||
var Item = this.NodesArr[i];
|
||||
if(Item.LastTime && (CurTime - Item.LastTime) < NODES_DELTA_CALC_HOUR * 3600 * 1000)
|
||||
CountAll++
|
||||
else
|
||||
if(Item.LastTimeGetNode && (CurTime - Item.LastTimeGetNode) < NODES_DELTA_CALC_HOUR * 3600 * 1000)
|
||||
CountAll++
|
||||
}
|
||||
global.CountAllNode = CountAll
|
||||
if(!global.STAT_MODE)
|
||||
return ;
|
||||
var StateTX = DApps.Accounts.DBStateTX.Read(0);
|
||||
if(StateTX)
|
||||
{
|
||||
var Delta = this.CurrentBlockNum - StateTX.BlockNum;
|
||||
ADD_TO_STAT("MAX:DELTA_TX", Delta)
|
||||
}
|
||||
var bHasCP = 0;
|
||||
if(CHECK_POINT.BlockNum)
|
||||
{
|
||||
var Block = this.ReadBlockHeaderDB(CHECK_POINT.BlockNum);
|
||||
if(Block && CompareArr(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 && CHECK_POINT.BlockNum && INFO.CheckPointHashDB && CompareArr(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 && 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++
|
||||
}
|
||||
ADD_TO_STAT("MAX:ALL_NODES", CountAll)
|
||||
ADD_TO_STAT("MAX:CONNECTED_NODES", Count)
|
||||
ADD_TO_STAT("MAX:HOT_NODES", CountHot)
|
||||
ADD_TO_STAT("MAX:HOT_OK", CountHotOK)
|
||||
ADD_TO_STAT("MAX:ACTUAL_OK", CountActualOK)
|
||||
ADD_TO_STAT("MAX:CHECK_POINT_OK", CountCP)
|
||||
ADD_TO_STAT("MAX:COUNTLH", CountLH)
|
||||
ADD_TO_STAT("MAX:HASH_OK", CountHash)
|
||||
ADD_TO_STAT("MAX:MIN_VERSION", CountVer)
|
||||
ADD_TO_STAT("MAX:STOP_GET", CountStop)
|
||||
ADD_TO_STAT("MAX:AUTOCORRECT", CountAutoCorrectTime)
|
||||
ADD_TO_STAT("MAX:TIME_DELTA", 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)
|
||||
ADD_TO_STAT("MAX:DELTA_GLOB_TIME", 100 + AvgGlobTime)
|
||||
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)
|
||||
ADD_TO_STAT("MAX:MEDIAN_GLOB_TIME", 100 + AvgGlobTimeM)
|
||||
ADD_TO_STAT("MAX:DISP_MEDIAN_GLOB_TIME", SumDeltaAvgM)
|
||||
}
|
||||
ADD_TO_STAT("MAX:DELTA_TIME_HOT", SumDeltaHot / CountHot)
|
||||
ADD_TO_STAT("MAX:DELTA_TIME_ACTUAL", SumDeltaActual / Count)
|
||||
ADD_TO_STAT("MAX:MEMORY_USAGE", process.memoryUsage().heapTotal / 1024 / 1024)
|
||||
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;
|
||||
ADD_TO_STAT("MAX:CPU_USER_MODE", Math.min(maxsum, SumUser - GlSumUser))
|
||||
ADD_TO_STAT("MAX:CPU_SYS_MODE", Math.min(maxsum, SumSys - GlSumSys))
|
||||
ADD_TO_STAT("MAX:CPU_IDLE_MODE", Math.min(maxsum, SumIdle - GlSumIdle))
|
||||
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
|
||||
{
|
||||
constructor(MaxTime, CheckName)
|
||||
{
|
||||
this.MetaMap1 = {}
|
||||
this.MetaMap2 = {}
|
||||
this.CheckName = CheckName
|
||||
setInterval(this.ShiftMapDirect.bind(this), MaxTime)
|
||||
}
|
||||
GetStrKey(Arr)
|
||||
{
|
||||
if(typeof Arr === "number" || typeof Arr === "string")
|
||||
{
|
||||
return Arr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetHexFromAddres(Arr);
|
||||
}
|
||||
throw "NOT RET!";
|
||||
}
|
||||
LoadValue(Arr, bStay)
|
||||
{
|
||||
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(glStopNode)
|
||||
return ;
|
||||
if(this.CheckName)
|
||||
{
|
||||
var Count = 0;
|
||||
for(var key in this.MetaMap2)
|
||||
{
|
||||
Count++
|
||||
}
|
||||
if(Count)
|
||||
{
|
||||
ADD_TO_STAT(this.CheckName, 1, 1)
|
||||
}
|
||||
}
|
||||
this.MetaMap2 = this.MetaMap1
|
||||
this.MetaMap1 = {}
|
||||
}
|
||||
Clear()
|
||||
{
|
||||
this.MetaMap2 = {}
|
||||
this.MetaMap1 = {}
|
||||
}
|
||||
};
|
||||
class STreeBuffer
|
||||
{
|
||||
constructor(MaxTime, CompareFunction, KeyType, CheckName)
|
||||
{
|
||||
this.KeyType = KeyType
|
||||
this.MetaTree1 = new RBTree(CompareFunction)
|
||||
this.MetaTree2 = new RBTree(CompareFunction)
|
||||
this.CheckName = CheckName
|
||||
setInterval(this.ShiftMapDirect.bind(this), MaxTime)
|
||||
}
|
||||
LoadValue(Hash, bStay)
|
||||
{
|
||||
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, Value)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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,BlockNum)
|
||||
{
|
||||
var MyHash = Map[BlockNum];
|
||||
if(!MyHash)
|
||||
{
|
||||
var Block = 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,BlockNum,Hash)
|
||||
{
|
||||
var MyHash = Map[BlockNum];
|
||||
if(!MyHash)
|
||||
{
|
||||
MyHash = DApps.Accounts.GetHashOrUndefined(BlockNum);
|
||||
Map[BlockNum] = MyHash;
|
||||
}
|
||||
if(MyHash)
|
||||
{
|
||||
if(!Hash)
|
||||
return "=ERR:NO=";
|
||||
if(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 = 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 = GetPowPower(shaarr(Body));
|
||||
var deltaTime = (Time[0] * 1000 + Time[1] / 1e6) / 1000;
|
||||
var DeltaData = (new Date() - StartData) / 1000;
|
||||
ToLog("power=" + power + " nonce=" + nonce + " TIME=" + deltaTime + " sec" + " DeltaData=" + DeltaData + " sec");
|
||||
return {time1:deltaTime, time2:DeltaData};
|
||||
};
|
||||
|
||||
function CreateHashBody(body,Num,Nonce)
|
||||
{
|
||||
body.writeUIntLE(Num, body.length - 12, 6);
|
||||
body.writeUIntLE(Nonce, body.length - 6, 6);
|
||||
return shaarr(body);
|
||||
};
|
||||
|
||||
function CreateHashBodyPOWInnerMinPower(arr,BlockNum,MinPow)
|
||||
{
|
||||
var nonce = 0;
|
||||
while(1)
|
||||
{
|
||||
var arrhash = CreateHashBody(arr, BlockNum, nonce);
|
||||
var power = GetPowPower(arrhash);
|
||||
if(power >= MinPow)
|
||||
{
|
||||
return nonce;
|
||||
}
|
||||
nonce++;
|
||||
}
|
||||
};
|
||||
1644
Source/core/block-exchange.js
Normal file
1644
Source/core/block-exchange.js
Normal file
File diff suppressed because it is too large
Load Diff
16
Source/core/block-loader-const.js
Normal file
16
Source/core/block-loader-const.js
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* @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.PERIOD_GET_BLOCK = 300, global.COUNT_HISTORY_BLOCKS_FOR_LOAD = 600, global.COUNT_BLOCKS_FOR_CHECK_POW = 50, global.MAX_DELTA_COUNT_SUM_FOR_LOAD = 10,
|
||||
global.MAX_COUNT_CHAIN_LOAD = 120, global.PACKET_ALIVE_PERIOD = 4 * CONSENSUS_PERIOD_TIME, global.PACKET_ALIVE_PERIOD_NEXT_NODE = PACKET_ALIVE_PERIOD / 2,
|
||||
global.MAX_BLOCK_SEND = 8, global.COUNT_TASK_FOR_NODE = 10, global.FORMAT_BLOCK_TRANSFER = "{ BlockNum:uint, TreeHash:hash, arrContent:[tr], }",
|
||||
global.WRK_BLOCK_TRANSFER = {}, global.MAX_ACCOUNTS_TRANSFER = 1024, global.MAX_SMARTS_TRANSFER = 10, global.TEST_NETWORK && (global.MAX_ACCOUNTS_TRANSFER = 128,
|
||||
global.MAX_SMARTS_TRANSFER = 10), global.FORMAT_REST_TRANSFER = "{ Result:uint, Version:uint, Arr:[arr200], ProofHash:hash, ProofArrL:<hash>, ProofArrR:<hash>, }",
|
||||
global.FORMAT_SMART_TRANSFER = "{ Result:uint, Arr:[tr], }";
|
||||
1503
Source/core/block-loader.js
Normal file
1503
Source/core/block-loader.js
Normal file
File diff suppressed because it is too large
Load Diff
364
Source/core/buffer.js
Normal file
364
Source/core/buffer.js
Normal file
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
* @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
|
||||
*/
|
||||
|
||||
|
||||
function Write(e,r,t,n,l)
|
||||
{
|
||||
if(!(e.len >= e.length))
|
||||
{
|
||||
if("number" == typeof t)
|
||||
throw ToLogTrace("ERRR StringFormat "), "ERR!!";
|
||||
var a = t;
|
||||
if("buffer" === a.substr(0, 6) && 6 < a.length)
|
||||
n = parseInt(a.substr(6)), a = "buffer";
|
||||
else
|
||||
if("arr" === a.substr(0, 3) && 3 < a.length)
|
||||
n = parseInt(a.substr(3)), a = "arr";
|
||||
else
|
||||
if("str" === a.substr(0, 3) && 3 < a.length)
|
||||
{
|
||||
var i = parseInt(a.substr(3));
|
||||
return r && e.write(r, e.len, i), void (e.len += i);
|
||||
}
|
||||
switch(a)
|
||||
{
|
||||
case "str":
|
||||
var f = toUTF8Array(r);
|
||||
65535 < (i = f.length) && (i = 0), e[e.len] = 255 & i, e[e.len + 1] = i >>> 8 & 255, e.len += 2;
|
||||
for(var s = 0; s < i; s++)
|
||||
e[e.len + s] = f[s];
|
||||
e.len += i;
|
||||
break;
|
||||
case "byte":
|
||||
r < 0 && (r = 0), e[e.len] = r, e.len += 1;
|
||||
break;
|
||||
case "double":
|
||||
e.writeDoubleLE(r, e.len, 8), e.len += 8;
|
||||
break;
|
||||
case "uint":
|
||||
r < 0 && (r = 0), 0xffffffffffff <= r && (r = 0), e.writeUIntLE(r, e.len, 6), e.len += 6;
|
||||
break;
|
||||
case "uint16":
|
||||
r < 0 && (r = 0), e[e.len] = 255 & r, e[e.len + 1] = r >>> 8 & 255, e.len += 2;
|
||||
break;
|
||||
case "uint32":
|
||||
r < 0 && (r = 0), e.writeUInt32LE(r, e.len, 4), e.len += 4;
|
||||
break;
|
||||
case "time":
|
||||
var u = r.valueOf();
|
||||
e.writeUIntLE(u, e.len, 6), e.len += 6;
|
||||
break;
|
||||
case "addres":
|
||||
case "hash":
|
||||
i = r ? Math.min(32, r.length) : 0;
|
||||
for(s = 0; s < i; s++)
|
||||
e[e.len + s] = r[s];
|
||||
e.len += 32;
|
||||
break;
|
||||
case "buffer":
|
||||
i = void 0 === n ? r.length : Math.min(n, r.length);
|
||||
for(s = 0; s < i; s++)
|
||||
e[e.len + s] = r[s];
|
||||
e.len += n;
|
||||
break;
|
||||
case "arr":
|
||||
i = r ? Math.min(n, r.length) : 0;
|
||||
for(s = 0; s < i; s++)
|
||||
e[e.len + s] = r[s];
|
||||
e.len += n;
|
||||
break;
|
||||
case "tr":
|
||||
i = r.length;
|
||||
MAX_TRANSACTION_SIZE > MAX_TRANSACTION_SIZE && (i = MAX_TRANSACTION_SIZE), e[e.len] = 255 & i, e[e.len + 1] = i >>> 8 & 255,
|
||||
e.len += 2;
|
||||
for(s = 0; s < i; s++)
|
||||
e[e.len + s] = r[s];
|
||||
e.len += i;
|
||||
break;
|
||||
case "data":
|
||||
i = r.length;
|
||||
e.writeUInt32LE(i, e.len, 4), e.len += 4;
|
||||
for(s = 0; s < i; s++)
|
||||
e[e.len + s] = r[s];
|
||||
e.len += i;
|
||||
break;
|
||||
case "hashSTR":
|
||||
var o = GetHexFromAddres(r);
|
||||
e.write(o, e.len, 64), e.len += 64;
|
||||
break;
|
||||
case "uintSTR":
|
||||
o = r.toString();
|
||||
e.write(o, e.len, 10), e.len += 10;
|
||||
break;
|
||||
default:
|
||||
l = l || {};
|
||||
var d = t.substr(0, 1);
|
||||
if("[" === d)
|
||||
{
|
||||
r && (i = r.length);
|
||||
var b = GetMiddleString(a);
|
||||
Write(e, i, "uint32");
|
||||
for(s = 0; s < i; s++)
|
||||
Write(e, r[s], b, void 0, l);
|
||||
}
|
||||
else
|
||||
if("<" === d)
|
||||
{
|
||||
r && (i = r.length);
|
||||
b = GetMiddleString(a);
|
||||
var h = 0, c = e.len;
|
||||
e.len += 4;
|
||||
for(s = 0; s < i; s++)
|
||||
r[s] && (h++, Write(e, s, "uint32"), Write(e, r[s], b, void 0, l));
|
||||
e.writeUInt32LE(h, c, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
if("{" !== d)
|
||||
throw "Bad write type params: " + a;
|
||||
var g = l[a];
|
||||
g || (g = GetAttributes(GetMiddleString(a)), l[a] = g);
|
||||
for(s = 0; s < g.length; s++)
|
||||
{
|
||||
var v = g[s];
|
||||
Write(e, r[v.Key], v.Value, void 0, l);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function Read(e,r,t,n,l)
|
||||
{
|
||||
var a;
|
||||
if("number" == typeof r)
|
||||
throw ToLogTrace("ERR StringFormat"), "ERRR!";
|
||||
var i = r;
|
||||
if("buffer" === i.substr(0, 6))
|
||||
6 < i.length ? (t = parseInt(i.substr(6)), i = "buffer") : t = 0;
|
||||
else
|
||||
if("arr" === i.substr(0, 3))
|
||||
3 < i.length ? (t = parseInt(i.substr(3)), i = "arr") : t = 0;
|
||||
else
|
||||
if("str" === i.substr(0, 3))
|
||||
{
|
||||
if(3 < i.length)
|
||||
{
|
||||
var f = parseInt(i.substr(3));
|
||||
a = e.toString("utf8", e.len, e.len + f), e.len += f;
|
||||
for(var s = - 1, u = a.length - 1; 0 <= u; u--)
|
||||
if(0 !== a.charCodeAt(u))
|
||||
{
|
||||
s = u;
|
||||
break;
|
||||
}
|
||||
return a = 0 <= s ? a.substr(0, u + 1) : "";
|
||||
}
|
||||
t = 0;
|
||||
}
|
||||
switch(i)
|
||||
{
|
||||
case "str":
|
||||
f = e.len + 2 <= e.length ? e[e.len] + 256 * e[e.len + 1] : 0, e.len += 2;
|
||||
var o = e.slice(e.len, e.len + f);
|
||||
a = Utf8ArrayToStr(o), e.len += f;
|
||||
break;
|
||||
case "byte":
|
||||
a = e.len + 1 <= e.length ? e[e.len] : 0, e.len += 1;
|
||||
break;
|
||||
case "double":
|
||||
a = e.len + 8 <= e.length ? e.readDoubleLE(e.len, 8) : 0, e.len += 8;
|
||||
break;
|
||||
case "uint":
|
||||
a = e.len + 6 <= e.length ? e.readUIntLE(e.len, 6) : 0, e.len += 6;
|
||||
break;
|
||||
case "uint16":
|
||||
a = e.len + 2 <= e.length ? e[e.len] + 256 * e[e.len + 1] : 0, e.len += 2;
|
||||
break;
|
||||
case "uint32":
|
||||
a = e.len + 4 <= e.length ? e.readUInt32LE(e.len, 4) : 0, e.len += 4;
|
||||
break;
|
||||
case "time":
|
||||
if(l)
|
||||
throw "Bad read type params: time - DisableTime ON";
|
||||
a = e.len + 6 <= e.length ? e.readUIntLE(e.len, 6) : 0, a = new Date(a), e.len += 6;
|
||||
break;
|
||||
case "addres":
|
||||
case "hash":
|
||||
a = [];
|
||||
for(u = 0; u < 32; u++)
|
||||
e.len + u <= e.length ? a[u] = e[e.len + u] : a[u] = 0;
|
||||
e.len += 32;
|
||||
break;
|
||||
case "buffer":
|
||||
case "arr":
|
||||
a = e.len + t <= e.length ? e.slice(e.len, e.len + t) : Buffer.alloc(t), e.len += t;
|
||||
break;
|
||||
case "tr":
|
||||
if(e.len + 1 >= e.length)
|
||||
{
|
||||
a = void 0;
|
||||
break;
|
||||
}
|
||||
f = e[e.len] + 256 * e[e.len + 1];
|
||||
e.len += 2, a = e.slice(e.len, e.len + f), e.len += f;
|
||||
break;
|
||||
case "data":
|
||||
(f = e.len + 4 <= e.length ? e.readUInt32LE(e.len, 4) : 0) > e.length - e.len - 4 && (f = 0), e.len += 4, a = e.slice(e.len,
|
||||
e.len + f), e.len += f;
|
||||
break;
|
||||
case "hashSTR":
|
||||
var d = e.toString("utf8", e.len, e.len + 64);
|
||||
a = GetAddresFromHex(d), e.len += 64;
|
||||
break;
|
||||
case "uintSTR":
|
||||
d = e.toString("utf8", e.len, e.len + 10);
|
||||
a = parseInt(d), e.len += 10;
|
||||
break;
|
||||
default:
|
||||
n = n || {};
|
||||
var b = i.substr(0, 1);
|
||||
if("[" === b || "<" === b)
|
||||
{
|
||||
var h = "<" === b;
|
||||
a = [];
|
||||
var c = GetMiddleString(i);
|
||||
for(f = Read(e, "uint32"), u = 0; u < f && e.len <= e.length; u++)
|
||||
{
|
||||
h ? a[Read(e, "uint32")] = Read(e, c, void 0, n, l) : a[u] = Read(e, c, void 0, n, l);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if("{" !== b)
|
||||
throw "Bad read type params: " + i;
|
||||
var g = n[i];
|
||||
g || (g = GetAttributes(GetMiddleString(i)), n[i] = g), a = {};
|
||||
for(u = 0; u < g.length; u++)
|
||||
{
|
||||
var v = g[u];
|
||||
a[v.Key] = Read(e, v.Value, void 0, n, l);
|
||||
}
|
||||
}
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
function BufWriteByte(e)
|
||||
{
|
||||
this[this.len] = e, this.len += 1;
|
||||
};
|
||||
|
||||
function BufWrite(e,r,t)
|
||||
{
|
||||
Write(this, e, r, t);
|
||||
};
|
||||
|
||||
function BufRead(e,r)
|
||||
{
|
||||
return Read(this, e, r);
|
||||
};
|
||||
|
||||
function GetNewBuffer(e)
|
||||
{
|
||||
var r = Buffer.alloc(e);
|
||||
return r.Read = BufRead.bind(r), r.Write = BufWrite.bind(r), r.len = 0, r;
|
||||
};
|
||||
|
||||
function GetReadBuffer(e)
|
||||
{
|
||||
var r = Buffer.from(e);
|
||||
return r.Read = BufRead.bind(r), r.Write = BufWrite.bind(r), r.len = 0, r;
|
||||
};
|
||||
|
||||
function GetObjectFromBuffer(e,r,t,n)
|
||||
{
|
||||
var l = Buffer.from(e);
|
||||
return l.len = 0, Read(l, r, void 0, t, n);
|
||||
};
|
||||
|
||||
function GetBufferFromObject(e,r,t,n,l)
|
||||
{
|
||||
var a = Buffer.alloc(t);
|
||||
return a.len = 0, Write(a, e, r, void 0, n), l || (a = a.slice(0, a.len)), a;
|
||||
};
|
||||
|
||||
function GetMiddleString(e)
|
||||
{
|
||||
return e.substr(1, e.length - 2);
|
||||
};
|
||||
|
||||
function GetMiddleString2(e,r,t)
|
||||
{
|
||||
for(var n = 0, l = "", a = 0; a < e.length; a++)
|
||||
{
|
||||
var i = e.substr(a, 1);
|
||||
if(" " !== i && "\n" !== i && (i !== r || 1 != ++n))
|
||||
{
|
||||
if(i === t && 0 === --n)
|
||||
break;
|
||||
n && (l += i);
|
||||
}
|
||||
}
|
||||
return l;
|
||||
};
|
||||
|
||||
function GetAttributeStrings(e)
|
||||
{
|
||||
for(var r = 0, t = [], n = "", l = 0; l < e.length; l++)
|
||||
{
|
||||
var a = e.substr(l, 1);
|
||||
if("{" === a)
|
||||
r++;
|
||||
else
|
||||
if("}" === a)
|
||||
r--;
|
||||
else
|
||||
{
|
||||
if("," === a && 0 === r)
|
||||
{
|
||||
0 < n.length && t.push(n), n = "";
|
||||
continue;
|
||||
}
|
||||
if(" " === a || "\n" === a)
|
||||
continue;
|
||||
}
|
||||
n += a;
|
||||
}
|
||||
return 0 < n.length && t.push(n), t;
|
||||
};
|
||||
|
||||
function GetKeyValueStrings(e)
|
||||
{
|
||||
for(var r = "", t = 0; t < e.length; t++)
|
||||
{
|
||||
var n = e.substr(t, 1);
|
||||
if(" " !== n && "\n" !== n)
|
||||
{
|
||||
if(":" === n)
|
||||
return {Key:r, Value:e.substr(t + 1)};
|
||||
r += n;
|
||||
}
|
||||
}
|
||||
throw "Error format Key:Value = " + e;
|
||||
};
|
||||
|
||||
function GetAttributes(e)
|
||||
{
|
||||
for(var r = [], t = GetAttributeStrings(e), n = 0; n < t.length; n++)
|
||||
{
|
||||
var l = GetKeyValueStrings(t[n]);
|
||||
r.push(l);
|
||||
}
|
||||
return r;
|
||||
};
|
||||
module.exports.GetNewBuffer = GetNewBuffer, module.exports.GetReadBuffer = GetReadBuffer, module.exports.alloc = GetNewBuffer,
|
||||
module.exports.from = GetReadBuffer, module.exports.Write = Write, module.exports.Read = Read, module.exports.GetObjectFromBuffer = GetObjectFromBuffer,
|
||||
module.exports.GetBufferFromObject = GetBufferFromObject;
|
||||
245
Source/core/code.js
Normal file
245
Source/core/code.js
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* @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";
|
||||
var fs = require("fs");
|
||||
const FORMAT_EVAL_SEND = "{MaxBlockNum:uint,Code:str,Sign:arr64}";
|
||||
module.exports = class CCode extends require("./base")
|
||||
{
|
||||
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
|
||||
CheckCreateDir(GetDataPath("Update"))
|
||||
}
|
||||
CheckLoadCodeTime()
|
||||
{
|
||||
if(START_LOAD_CODE.StartLoadNode && START_LOAD_CODE.StartLoadVersionNum)
|
||||
{
|
||||
var Delta = new Date() - START_LOAD_CODE.StartLoadVersionNumTime;
|
||||
if(Delta > 20 * 1000)
|
||||
{
|
||||
ToError("Cannot load code version:" + START_LOAD_CODE.StartLoadVersionNum + " from node: " + START_LOAD_CODE.StartLoadNode.ip + ":" + START_LOAD_CODE.StartLoadNode.port)
|
||||
this.ClearLoadCode()
|
||||
}
|
||||
}
|
||||
}
|
||||
ClearLoadCode()
|
||||
{
|
||||
START_LOAD_CODE.StartLoad = undefined
|
||||
START_LOAD_CODE.StartLoadVersionNum = 0
|
||||
START_LOAD_CODE.StartLoadVersionNumTime = 0
|
||||
}
|
||||
StartLoadCode(Node, CodeVersion)
|
||||
{
|
||||
var VersionNum = CodeVersion.VersionNum;
|
||||
START_LOAD_CODE.StartLoad = CodeVersion
|
||||
START_LOAD_CODE.StartLoadNode = Node
|
||||
START_LOAD_CODE.StartLoadVersionNum = VersionNum
|
||||
START_LOAD_CODE.StartLoadVersionNumTime = new Date()
|
||||
var fname = 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 || !START_LOAD_CODE.StartLoad)
|
||||
return ;
|
||||
var fname = GetDataPath("Update/wallet-" + VersionNum + ".zip");
|
||||
if(!fs.existsSync(fname))
|
||||
{
|
||||
var Hash = shaarr(Info.Data);
|
||||
if(CompareArr(Hash, 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
|
||||
{
|
||||
ToError("Error check hash of version code :" + 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.START_LOAD_CODE.StartLoad)
|
||||
{
|
||||
global.CODE_VERSION = START_LOAD_CODE.StartLoad
|
||||
this.ClearLoadCode()
|
||||
}
|
||||
}
|
||||
SetNewCodeVersion(Data, PrivateKey)
|
||||
{
|
||||
var fname = GetDataPath("ToUpdate/wallet.zip");
|
||||
if(fs.existsSync(fname))
|
||||
{
|
||||
var fname2 = GetDataPath("Update/wallet-" + Data.VersionNum + ".zip");
|
||||
if(fs.existsSync(fname2))
|
||||
{
|
||||
fs.unlinkSync(fname2)
|
||||
}
|
||||
var data = fs.readFileSync(fname);
|
||||
var Hash = 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 = 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;
|
||||
ToLog("Check file:" + Name);
|
||||
if(fs.existsSync(Path))
|
||||
{
|
||||
if(StartNum === Num)
|
||||
{
|
||||
ToLog("UnpackCodeFile:" + Name);
|
||||
UnpackCodeFile(Path);
|
||||
if(StartNum % 2 === 0)
|
||||
{
|
||||
global.RestartNode(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
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();
|
||||
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();
|
||||
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");
|
||||
}
|
||||
}
|
||||
SERVER.StopServer();
|
||||
SERVER.StopNode();
|
||||
StopChildProcess();
|
||||
ToLog("****************************************** RESTART!!!");
|
||||
ToLog("EXIT 1");
|
||||
};
|
||||
|
||||
function DoExit()
|
||||
{
|
||||
ToLog("EXIT 2");
|
||||
if(global.nw || global.NWMODE)
|
||||
{
|
||||
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});
|
||||
}
|
||||
ToLog("EXIT 3");
|
||||
process.exit(0);
|
||||
};
|
||||
1595
Source/core/connect.js
Normal file
1595
Source/core/connect.js
Normal file
File diff suppressed because it is too large
Load Diff
330
Source/core/constant.js
Normal file
330
Source/core/constant.js
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* @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.UPDATE_CODE_VERSION_NUM = 1131;
|
||||
global.MIN_CODE_VERSION_NUM = 1114;
|
||||
global.MINING_VERSION_NUM = 0;
|
||||
global.InitParamsArg = InitParamsArg;
|
||||
global.CONST_NAME_ARR = ["AUTO_CORRECT_TIME", "DELTA_CURRENT_TIME", "COMMON_KEY", "NODES_NAME", "SERVER_PRIVATE_KEY_HEX", "USE_NET_FOR_SERVER_ADDRES",
|
||||
"NET_WORK_MODE", "STAT_MODE", "MAX_STAT_PERIOD", "LISTEN_IP", "HTTP_PORT_NUMBER", "HTTP_PORT_PASSWORD", "HTTP_IP_CONNECT",
|
||||
"WALLET_NAME", "WALLET_DESCRIPTION", "USE_API_WALLET", "USE_API_V1", "USE_HARD_API_V2", "COUNT_VIEW_ROWS", "USE_HINT", "ALL_VIEW_ROWS",
|
||||
"ALL_LOG_TO_CLIENT", "LOG_LEVEL", "USE_MINING", "MINING_START_TIME", "MINING_PERIOD_TIME", "POW_MAX_PERCENT", "COUNT_MINING_CPU",
|
||||
"SIZE_MINING_MEMORY", "POW_RUN_COUNT", "USE_AUTO_UPDATE", "RESTART_PERIOD_SEC", "MAX_GRAY_CONNECTIONS_TO_SERVER", "TRANSACTION_PROOF_COUNT",
|
||||
"UPDATE_NUM_COMPLETE", "LIMIT_SEND_TRAFIC", "WATCHDOG_DEV", "ADDRLIST_MODE", "CheckPointDelta", "MIN_VER_STAT", "DEBUG_WALLET",
|
||||
"HTTP_HOSTING_PORT", "HTTPS_HOSTING_DOMAIN", "HTTP_MAX_COUNT_ROWS", "HTTP_ADMIN_PASSORD", "WATCHDOG_BADACCOUNT", "RESYNC_CONDITION",
|
||||
"MAX_CONNECTIONS_COUNT", "TRUST_PROCESS_COUNT", "REST_START_COUNT", "LOAD_TO_BEGIN", ];
|
||||
global.MAX_LENGTH_SENDER_MAP = 3000;
|
||||
global.DELTA_START_SENDER_MAP = 24;
|
||||
global.NODES_DELTA_CALC_HOUR = 4;
|
||||
global.USE_API_WALLET = 1;
|
||||
global.USE_API_V1 = 1;
|
||||
global.USE_HARD_API_V2 = 0;
|
||||
global.USE_TICKET = 0;
|
||||
global.USE_CHECK_SENDING = 1;
|
||||
global.USE_LEVEL_WAY = 0;
|
||||
global.TR_TICKET_HASH_LENGTH = 10;
|
||||
global.BLOCKNUM_TICKET_ALGO = 16070000;
|
||||
global.WATCHDOG_BADACCOUNT = 1;
|
||||
global.WATCHDOG_DEV = 0;
|
||||
global.RESYNC_CONDITION = {"OWN_BLOCKS":20, "K_POW":5};
|
||||
global.REST_BLOCK_SCALE = 1000;
|
||||
global.REST_START_COUNT = 1000;
|
||||
global.LOAD_TO_BEGIN = 2;
|
||||
global.DEBUG_WALLET = 0;
|
||||
global.CHECK_GLOBAL_TIME = 1;
|
||||
global.AUTO_CORRECT_TIME = 1;
|
||||
global.DELTA_CURRENT_TIME = 0;
|
||||
global.NODES_NAME = "";
|
||||
global.COMMON_KEY = "";
|
||||
global.SERVER_PRIVATE_KEY_HEX = undefined;
|
||||
global.USE_NET_FOR_SERVER_ADDRES = 1;
|
||||
global.NET_WORK_MODE = undefined;
|
||||
global.STAT_MODE = 0;
|
||||
global.MAX_STAT_PERIOD = 1 * 3600;
|
||||
global.UPDATE_NUM_COMPLETE = 0;
|
||||
global.WALLET_NAME = "TERA";
|
||||
global.WALLET_DESCRIPTION = "";
|
||||
global.USE_MINING = 0;
|
||||
global.POW_MAX_PERCENT = 50;
|
||||
global.POW_RUN_COUNT = 5000;
|
||||
global.POWRunPeriod = 1;
|
||||
global.CheckPointDelta = 20;
|
||||
global.ALL_LOG_TO_CLIENT = 1;
|
||||
global.LOG_LEVEL = 1;
|
||||
global.LIMIT_SEND_TRAFIC = 0;
|
||||
global.COUNT_VIEW_ROWS = 20;
|
||||
global.MIN_VER_STAT = 0;
|
||||
global.STOPGETBLOCK = 0;
|
||||
global.RESTART_PERIOD_SEC = 0;
|
||||
global.HARD_PACKET_PERIOD120 = 160;
|
||||
global.MINING_START_TIME = "";
|
||||
global.MINING_PERIOD_TIME = "";
|
||||
global.CHECK_RUN_MINING = 21 * 1000;
|
||||
global.CHECK_STOP_CHILD_PROCESS = 10 * 1000;
|
||||
global.COUNT_MINING_CPU = 0;
|
||||
global.SIZE_MINING_MEMORY = 0;
|
||||
global.HTTP_HOSTING_PORT = 0;
|
||||
global.HTTPS_HOSTING_DOMAIN = "";
|
||||
global.HTTP_MAX_COUNT_ROWS = 20;
|
||||
global.HTTP_ADMIN_PASSORD = "";
|
||||
require("./startlib.js");
|
||||
global.MIN_POWER_POW_HANDSHAKE = 12;
|
||||
global.USE_HINT = 0;
|
||||
global.ALL_VIEW_ROWS = 0;
|
||||
global.COUNT_BLOCK_PROOF = 300;
|
||||
global.COUNT_NODE_PROOF = 10;
|
||||
global.MIN_POWER_POW_MSG = 2;
|
||||
global.MEM_POOL_MSG_COUNT = 1000;
|
||||
global.MAX_LEVEL_SPECIALIZATION = 24;
|
||||
global.MIN_CONNECT_CHILD = 2;
|
||||
global.MAX_CONNECT_CHILD = 7;
|
||||
global.MAX_CONNECTIONS_COUNT = 1000;
|
||||
global.TRUST_PROCESS_COUNT = 80000;
|
||||
global.MAX_NODES_RETURN = 100;
|
||||
global.MAX_WAIT_PERIOD_FOR_STATUS = 10 * 1000;
|
||||
global.MAX_GRAY_CONNECTIONS_TO_SERVER = 10;
|
||||
global.MAX_PACKET_LENGTH = 450 * 1024;
|
||||
global.COUNT_BLOCKS_FOR_LOAD = 600;
|
||||
global.TR_LEN = 100;
|
||||
global.BLOCK_PROCESSING_LENGTH = 8;
|
||||
global.BLOCK_PROCESSING_LENGTH2 = BLOCK_PROCESSING_LENGTH * 2;
|
||||
global.CONSENSUS_PERIOD_TIME = 1000;
|
||||
global.MAX_BLOCK_SIZE = 130 * 1024;
|
||||
global.MAX_TRANSACTION_SIZE = 65535;
|
||||
global.MIN_TRANSACTION_SIZE = 32;
|
||||
global.MAX_TRANSACTION_COUNT = 2000;
|
||||
global.MAX_TRANSACTION_LIMIT = 250;
|
||||
global.MIN_POWER_POW_TR = 10;
|
||||
if(global.MIN_POWER_POW_BL === undefined)
|
||||
global.MIN_POWER_POW_BL = 5;
|
||||
global.GENERATE_BLOCK_ACCOUNT = 0;
|
||||
global.TOTAL_SUPPLY_TERA = 1e9;
|
||||
global.TRANSACTION_PROOF_COUNT = 1000 * 1000;
|
||||
global.MIN_POWER_POW_ACC_CREATE = 16;
|
||||
global.START_MINING = 2 * 1000 * 1000;
|
||||
global.REF_PERIOD_MINING = 1 * 1000 * 1000;
|
||||
global.DELTA_BLOCK_ACCOUNT_HASH = 1000;
|
||||
global.PERIOD_ACCOUNT_HASH = 50;
|
||||
global.START_BLOCK_ACCOUNT_HASH = 14500000;
|
||||
global.START_BLOCK_ACCOUNT_HASH3 = 24015000;
|
||||
global.NEW_ACCOUNT_INCREMENT = 22305000;
|
||||
global.NEW_BLOCK_REWARD1 = 22500000;
|
||||
global.NEW_FORMULA_START = 32000000;
|
||||
global.NEW_FORMULA_KTERA = 3;
|
||||
global.NEW_FORMULA_TARGET1 = 43000000;
|
||||
global.NEW_FORMULA_TARGET2 = 45000000;
|
||||
global.BLOCK_COUNT_IN_MEMORY = 40;
|
||||
global.HISTORY_BLOCK_COUNT = 40;
|
||||
global.MAX_SIZE_LOG = 200 * 1024 * 1024;
|
||||
global.READ_ONLY_DB = 0;
|
||||
global.USE_CHECK_SAVE_DB = 1;
|
||||
global.START_NETWORK_DATE = 1530446400000;
|
||||
global.NETWORK = "TERA-MAIN";
|
||||
global.DEF_MAJOR_VERSION = "0001";
|
||||
global.SMART_BLOCKNUM_START = 10000000;
|
||||
global.PRICE_DAO = function (BlockNum)
|
||||
{
|
||||
return {NewAccount:10, NewSmart:100, NewTokenSmart:10000};
|
||||
};
|
||||
if(global.LOCAL_RUN)
|
||||
{
|
||||
var Num = Date.now() - 300 * 1000;
|
||||
global.START_NETWORK_DATE = Math.trunc(Num / 1000) * 1000;
|
||||
}
|
||||
global.NEW_SIGN_TIME = 25500000;
|
||||
InitParamsArg();
|
||||
if(global.LOCAL_RUN)
|
||||
{
|
||||
global.REST_BLOCK_SCALE = 100;
|
||||
global.DELTA_BLOCK_ACCOUNT_HASH = 30;
|
||||
global.PERIOD_ACCOUNT_HASH = 10;
|
||||
global.START_BLOCK_ACCOUNT_HASH = 1;
|
||||
global.START_BLOCK_ACCOUNT_HASH3 = 1;
|
||||
global.BLOCKNUM_TICKET_ALGO = 1;
|
||||
global.SMART_BLOCKNUM_START = 0;
|
||||
global.START_MINING = 60;
|
||||
global.REF_PERIOD_MINING = 10;
|
||||
global.TEST_TRANSACTION_GENERATE = 0;
|
||||
global.MIN_POWER_POW_TR = 8;
|
||||
global.MIN_POWER_POW_ACC_CREATE = 8;
|
||||
global.NEW_ACCOUNT_INCREMENT = 1;
|
||||
global.NEW_BLOCK_REWARD1 = 1;
|
||||
global.NEW_FORMULA_START = 1;
|
||||
global.NEW_FORMULA_KTERA = 3;
|
||||
global.NEW_FORMULA_TARGET1 = 0;
|
||||
global.NEW_FORMULA_TARGET2 = 1;
|
||||
NETWORK = "LOCAL";
|
||||
global.ALL_VIEW_ROWS = 1;
|
||||
global.COUNT_NODE_PROOF = 1;
|
||||
global.NEW_SIGN_TIME = 0;
|
||||
}
|
||||
else
|
||||
if(global.TEST_NETWORK)
|
||||
{
|
||||
global.REST_BLOCK_SCALE = 100;
|
||||
var Num = Date.now() - 50 * 1000;
|
||||
console.log("CURRENT NUM: " + (Math.trunc(Num / 1000) * 1000));
|
||||
global.SMART_BLOCKNUM_START = 0;
|
||||
global.START_NETWORK_DATE = 1550843168000 + 1000 * 1000;
|
||||
global.START_MINING = 1000;
|
||||
global.REF_PERIOD_MINING = 1000;
|
||||
global.MIN_POWER_POW_ACC_CREATE = 8;
|
||||
global.TRANSACTION_PROOF_COUNT = 200 * 1000;
|
||||
global.MAX_SIZE_LOG = 20 * 1024 * 1024;
|
||||
global.START_BLOCK_ACCOUNT_HASH = 1000;
|
||||
global.START_BLOCK_ACCOUNT_HASH3 = 2356000;
|
||||
global.BLOCKNUM_TICKET_ALGO = 1;
|
||||
global.WALLET_NAME = "TEST";
|
||||
NETWORK = "TERA-TEST2";
|
||||
if(global.START_PORT_NUMBER === undefined)
|
||||
global.START_PORT_NUMBER = 40000;
|
||||
global.ALL_VIEW_ROWS = 1;
|
||||
global.NEW_ACCOUNT_INCREMENT = 1903000;
|
||||
global.NEW_BLOCK_REWARD1 = 1905000;
|
||||
global.NEW_FORMULA_START = 11402000;
|
||||
global.NEW_FORMULA_KTERA = 3;
|
||||
global.NEW_FORMULA_TARGET1 = 11403000;
|
||||
global.NEW_FORMULA_TARGET2 = 11405000;
|
||||
global.COUNT_NODE_PROOF = 8;
|
||||
global.REST_START_COUNT = 10000;
|
||||
global.NEW_SIGN_TIME = 4859000;
|
||||
global.MAX_LENGTH_SENDER_MAP = 100;
|
||||
global.DELTA_START_SENDER_MAP = 12;
|
||||
}
|
||||
if(global.LOCAL_RUN)
|
||||
{
|
||||
global.BLOCKNUM_TICKET_ALGO = 0;
|
||||
global.MIN_POWER_POW_TR = 0;
|
||||
global.AUTO_CORRECT_TIME = 0;
|
||||
global.CHECK_GLOBAL_TIME = 0;
|
||||
}
|
||||
global.GetNetworkName = function ()
|
||||
{
|
||||
return NETWORK + "-" + DEF_MAJOR_VERSION;
|
||||
};
|
||||
global.DEF_VERSION = DEF_MAJOR_VERSION + "." + UPDATE_CODE_VERSION_NUM;
|
||||
global.DEF_CLIENT = "TERA-CORE";
|
||||
global.FIRST_TIME_BLOCK = START_NETWORK_DATE;
|
||||
global.START_BLOCK_RUN = 0;
|
||||
if(global.START_IP === undefined)
|
||||
global.START_IP = "";
|
||||
if(global.LISTEN_IP === undefined)
|
||||
global.LISTEN_IP = "0.0.0.0";
|
||||
if(global.START_PORT_NUMBER === undefined)
|
||||
global.START_PORT_NUMBER = 30000;
|
||||
if(global.HTTP_PORT_PASSWORD === undefined)
|
||||
global.HTTP_PORT_PASSWORD = "";
|
||||
if(global.HTTP_IP_CONNECT === undefined)
|
||||
global.HTTP_IP_CONNECT = "";
|
||||
if(global.USE_AUTO_UPDATE === undefined)
|
||||
global.USE_AUTO_UPDATE = 1;
|
||||
if(global.USE_PARAM_JS === undefined)
|
||||
global.USE_PARAM_JS = 1;
|
||||
if(global.DATA_PATH === undefined)
|
||||
global.DATA_PATH = "";
|
||||
if(global.CREATE_ON_START === undefined)
|
||||
global.CREATE_ON_START = false;
|
||||
if(global.LOCAL_RUN === undefined)
|
||||
global.LOCAL_RUN = 0;
|
||||
if(global.CODE_PATH === undefined)
|
||||
global.CODE_PATH = process.cwd();
|
||||
if(global.DEBUG_MODE === undefined)
|
||||
global.DEBUG_MODE = 0;
|
||||
global.DEBUG_MODE = 0;
|
||||
if(typeof window === 'object')
|
||||
{
|
||||
window.RUN_CLIENT = 0;
|
||||
window.RUN_SERVER = 1;
|
||||
}
|
||||
global.RUN_CLIENT = 0;
|
||||
global.RUN_SERVER = 1;
|
||||
|
||||
function InitParamsArg()
|
||||
{
|
||||
for(var i = 1; i < process.argv.length; i++)
|
||||
{
|
||||
var str0 = process.argv[i];
|
||||
var str = str0.toUpperCase();
|
||||
if(str.substr(0, 9) == "HTTPPORT:")
|
||||
{
|
||||
global.HTTP_PORT_NUMBER = parseInt(str.substr(9));
|
||||
}
|
||||
else
|
||||
if(str.substr(0, 9) == "PASSWORD:")
|
||||
{
|
||||
global.HTTP_PORT_PASSWORD = str0.substr(9);
|
||||
}
|
||||
else
|
||||
if(str.substr(0, 5) == "PATH:")
|
||||
global.DATA_PATH = str0.substr(5);
|
||||
else
|
||||
if(str.substr(0, 5) == "PORT:")
|
||||
global.START_PORT_NUMBER = parseInt(str.substr(5));
|
||||
else
|
||||
if(str.substr(0, 3) == "IP:")
|
||||
global.START_IP = str.substr(3);
|
||||
else
|
||||
if(str.substr(0, 7) == "LISTEN:")
|
||||
global.LISTEN_IP = str.substr(7);
|
||||
else
|
||||
if(str.substr(0, 8) == "HOSTING:")
|
||||
{
|
||||
global.HTTP_HOSTING_PORT = parseInt(str.substr(8));
|
||||
}
|
||||
else
|
||||
if(str.substr(0, 13) == "STARTNETWORK:")
|
||||
{
|
||||
global.START_NETWORK_DATE = parseInt(str.substr(13));
|
||||
console.log("START_NETWORK_DATE: " + START_NETWORK_DATE);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(str)
|
||||
{
|
||||
case "CHILDPOW":
|
||||
global.CHILD_POW = true;
|
||||
break;
|
||||
case "ADDRLIST":
|
||||
global.ADDRLIST_MODE = true;
|
||||
break;
|
||||
case "CREATEONSTART":
|
||||
global.CREATE_ON_START = true;
|
||||
break;
|
||||
case "LOCALRUN":
|
||||
global.LOCAL_RUN = 1;
|
||||
break;
|
||||
case "TESTRUN":
|
||||
global.TEST_NETWORK = 1;
|
||||
break;
|
||||
case "NOLOCALRUN":
|
||||
global.LOCAL_RUN = 0;
|
||||
break;
|
||||
case "NOAUTOUPDATE":
|
||||
global.USE_AUTO_UPDATE = 0;
|
||||
break;
|
||||
case "NOPARAMJS":
|
||||
global.USE_PARAM_JS = 0;
|
||||
break;
|
||||
case "READONLYDB":
|
||||
global.READ_ONLY_DB = 1;
|
||||
break;
|
||||
case "NWMODE":
|
||||
global.NWMODE = 1;
|
||||
break;
|
||||
case "NOALIVE":
|
||||
global.NOALIVE = 1;
|
||||
break;
|
||||
case "DEV_MODE":
|
||||
global.DEV_MODE = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
1106
Source/core/crypto-library.js
Normal file
1106
Source/core/crypto-library.js
Normal file
File diff suppressed because it is too large
Load Diff
1193
Source/core/db/block-db.js
Normal file
1193
Source/core/db/block-db.js
Normal file
File diff suppressed because it is too large
Load Diff
256
Source/core/db/db-row.js
Normal file
256
Source/core/db/db-row.js
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* @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";
|
||||
const fs = require('fs');
|
||||
module.exports = class CDBState extends require("./db")
|
||||
{
|
||||
constructor(FileName, DataSize, Format, bReadOnly)
|
||||
{
|
||||
super()
|
||||
this.FileName = FileName
|
||||
this.DataSize = DataSize
|
||||
this.Format = Format
|
||||
this.WorkStruct = {}
|
||||
var FI = this.OpenDBFile(this.FileName, !bReadOnly);
|
||||
this.FileNameFull = FI.fname
|
||||
this.LastHash = undefined
|
||||
this.WasUpdate = 1
|
||||
this.BufMap = {}
|
||||
this.BufMapCount = 0
|
||||
setInterval(this.CheckBufMap.bind(this), 1000)
|
||||
}
|
||||
GetMaxNum()
|
||||
{
|
||||
var FI = this.OpenDBFile(this.FileName);
|
||||
var Num = Math.floor(FI.size / this.DataSize) - 1;
|
||||
return Num;
|
||||
}
|
||||
CheckNewNum(Data)
|
||||
{
|
||||
if(Data.Num === undefined)
|
||||
Data.Num = this.GetMaxNum() + 1
|
||||
}
|
||||
Write(Data, RetBuf)
|
||||
{
|
||||
var startTime = process.hrtime();
|
||||
this.LastHash = undefined
|
||||
this.WasUpdate = 1
|
||||
this.CheckNewNum(Data)
|
||||
Data.Num = Math.trunc(Data.Num)
|
||||
this.DeleteMap(Data.Num)
|
||||
var BufWrite = BufLib.GetBufferFromObject(Data, this.Format, this.DataSize, this.WorkStruct, 1);
|
||||
var Position = Data.Num * this.DataSize;
|
||||
var FI = this.OpenDBFile(this.FileName, 1);
|
||||
var written = fs.writeSync(FI.fd, BufWrite, 0, BufWrite.length, Position);
|
||||
if(written !== BufWrite.length)
|
||||
{
|
||||
TO_ERROR_LOG("DB-ROW", 10, "Error write to file:" + written + " <> " + BufWrite.length)
|
||||
return false;
|
||||
}
|
||||
if(RetBuf)
|
||||
{
|
||||
RetBuf.Buf = BufWrite
|
||||
}
|
||||
if(Position >= FI.size)
|
||||
{
|
||||
FI.size = Position + this.DataSize
|
||||
}
|
||||
ADD_TO_STAT_TIME("ROWS_WRITE_MS", startTime)
|
||||
ADD_TO_STAT("ROWS_WRITE")
|
||||
return true;
|
||||
}
|
||||
Read(Num, GetBufOnly)
|
||||
{
|
||||
Num = Math.trunc(Num)
|
||||
var Data;
|
||||
if(isNaN(Num) || Num < 0 || Num > this.GetMaxNum())
|
||||
{
|
||||
return undefined;
|
||||
}
|
||||
var BufRead = this.GetMap(Num);
|
||||
if(!BufRead)
|
||||
{
|
||||
BufRead = BufLib.GetNewBuffer(this.DataSize)
|
||||
var Position = Num * this.DataSize;
|
||||
var FI = this.OpenDBFile(this.FileName);
|
||||
var bytesRead = fs.readSync(FI.fd, BufRead, 0, BufRead.length, Position);
|
||||
if(bytesRead !== BufRead.length)
|
||||
return undefined;
|
||||
this.SetMap(Num, BufRead)
|
||||
}
|
||||
if(GetBufOnly)
|
||||
{
|
||||
return BufRead;
|
||||
}
|
||||
try
|
||||
{
|
||||
Data = BufLib.GetObjectFromBuffer(BufRead, this.Format, this.WorkStruct)
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
ToLog("DBROW:" + e)
|
||||
return undefined;
|
||||
}
|
||||
Data.Num = Num
|
||||
return Data;
|
||||
}
|
||||
GetRows(start, count)
|
||||
{
|
||||
var arr = [];
|
||||
for(var num = start; num < start + count; num++)
|
||||
{
|
||||
var Data = this.Read(num);
|
||||
if(!Data)
|
||||
break;
|
||||
arr.push(Data)
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
Truncate(LastNum)
|
||||
{
|
||||
var startTime = process.hrtime();
|
||||
LastNum = Math.trunc(LastNum)
|
||||
var Position = (LastNum + 1) * this.DataSize;
|
||||
if(Position < 0)
|
||||
Position = 0
|
||||
var FI = this.OpenDBFile(this.FileName, 1);
|
||||
if(Position < FI.size)
|
||||
{
|
||||
this.LastHash = undefined
|
||||
this.WasUpdate = 1
|
||||
if(LastNum < 0)
|
||||
ToLog("Truncate " + this.FileName + " from 0", 2)
|
||||
FI.size = Position
|
||||
fs.ftruncateSync(FI.fd, FI.size)
|
||||
this.BufMap = {}
|
||||
this.BufMapCount = 0
|
||||
}
|
||||
ADD_TO_STAT_TIME("ROWS_WRITE_MS", startTime)
|
||||
}
|
||||
DeleteHistory(BlockNumFrom)
|
||||
{
|
||||
var MaxNum = this.GetMaxNum();
|
||||
if(MaxNum === - 1)
|
||||
return ;
|
||||
for(var num = MaxNum; num >= 0; num--)
|
||||
{
|
||||
var ItemCheck = this.Read(num);
|
||||
if(!ItemCheck)
|
||||
break;
|
||||
if(ItemCheck.BlockNum < BlockNumFrom)
|
||||
{
|
||||
if(num < MaxNum)
|
||||
{
|
||||
this.Truncate(num)
|
||||
}
|
||||
return ;
|
||||
}
|
||||
}
|
||||
this.Truncate( - 1)
|
||||
}
|
||||
FastFindBlockNum(BlockNum)
|
||||
{
|
||||
var MaxNum = this.GetMaxNum();
|
||||
if(MaxNum === - 1)
|
||||
return ;
|
||||
var StartNum = 0;
|
||||
var EndNum = MaxNum;
|
||||
var CurNum = Math.trunc(MaxNum / 2);
|
||||
while(true)
|
||||
{
|
||||
var Item = this.Read(CurNum);
|
||||
if(Item)
|
||||
{
|
||||
if(Item.BlockNum > BlockNum)
|
||||
{
|
||||
EndNum = CurNum - 1
|
||||
var Delta = CurNum - StartNum;
|
||||
if(Delta === 0)
|
||||
return "NoHistory";
|
||||
Delta = Math.trunc((1 + Delta) / 2)
|
||||
CurNum = CurNum - Delta
|
||||
}
|
||||
else
|
||||
if(Item.BlockNum < BlockNum)
|
||||
{
|
||||
StartNum = CurNum + 1
|
||||
var Delta = EndNum - CurNum;
|
||||
if(Delta === 0)
|
||||
return "NoPresent";
|
||||
Delta = Math.trunc((1 + Delta) / 2)
|
||||
CurNum = CurNum + Delta
|
||||
}
|
||||
else
|
||||
if(Item.BlockNum === BlockNum)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Error read num";
|
||||
return ;
|
||||
}
|
||||
}
|
||||
var num = CurNum;
|
||||
while(true)
|
||||
{
|
||||
num--
|
||||
if(num < 0)
|
||||
return CurNum;
|
||||
var Item = this.Read(num);
|
||||
if(Item)
|
||||
{
|
||||
if(Item.BlockNum === BlockNum)
|
||||
CurNum = num
|
||||
else
|
||||
return CurNum;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw "Error read num";
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
SetMap(Num, Value)
|
||||
{
|
||||
this.BufMap[Num] = Value
|
||||
this.BufMapCount++
|
||||
}
|
||||
GetMap(Num)
|
||||
{
|
||||
return this.BufMap[Num];
|
||||
}
|
||||
DeleteMap(Num)
|
||||
{
|
||||
if(this.BufMap[Num])
|
||||
{
|
||||
delete this.BufMap[Num]
|
||||
this.BufMapCount--
|
||||
}
|
||||
}
|
||||
CheckBufMap()
|
||||
{
|
||||
if(this.BufMapCount > 1000)
|
||||
{
|
||||
this.ClearBufMap()
|
||||
}
|
||||
}
|
||||
ClearBufMap()
|
||||
{
|
||||
this.BufMap = {}
|
||||
this.BufMapCount = 0
|
||||
}
|
||||
Close()
|
||||
{
|
||||
this.ClearBufMap()
|
||||
this.CloseDBFile(this.FileName)
|
||||
}
|
||||
};
|
||||
120
Source/core/db/db.js
Normal file
120
Source/core/db/db.js
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* @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";
|
||||
const fs = require('fs');
|
||||
module.exports = class
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
this.DBMap = {}
|
||||
}
|
||||
CheckPathDB()
|
||||
{
|
||||
var Path = GetDataPath("DB");
|
||||
CheckCreateDir(Path)
|
||||
}
|
||||
CloseDBFile(name, bdelete)
|
||||
{
|
||||
this.LastHash = undefined
|
||||
this.WasUpdate = 1
|
||||
var Item = this.DBMap[name];
|
||||
if(Item)
|
||||
{
|
||||
let bDelete = bdelete;
|
||||
let Name = name;
|
||||
fs.close(Item.fd, function (err)
|
||||
{
|
||||
if(!err)
|
||||
{
|
||||
if(bDelete)
|
||||
{
|
||||
var fname = GetDataPath("DB/" + Name);
|
||||
fs.unlink(fname, function (err)
|
||||
{
|
||||
if(err)
|
||||
ToLog(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ToLog(err)
|
||||
}
|
||||
})
|
||||
delete this.DBMap[name]
|
||||
}
|
||||
}
|
||||
OpenDBFile(name, bWrite, bExist)
|
||||
{
|
||||
if(bWrite && global.READ_ONLY_DB)
|
||||
{
|
||||
ToLogTrace("CANNOT WRITE - DB IN READ_ONLY MODE!!!")
|
||||
process.exit()
|
||||
}
|
||||
if(bWrite)
|
||||
CheckStartOneProcess(name + "-run")
|
||||
this.LastHash = undefined
|
||||
this.WasUpdate = 1
|
||||
var Item = this.DBMap[name];
|
||||
if(Item === undefined)
|
||||
{
|
||||
if(!this.WasCheckPathDB)
|
||||
{
|
||||
this.CheckPathDB()
|
||||
this.WasCheckPathDB = true
|
||||
}
|
||||
var fname = GetDataPath("DB/" + name);
|
||||
if(!fs.existsSync(fname))
|
||||
{
|
||||
if(bExist)
|
||||
{
|
||||
this.DBMap[name] = null
|
||||
return null;
|
||||
}
|
||||
var fd = fs.openSync(fname, "w+");
|
||||
fs.closeSync(fd)
|
||||
}
|
||||
var fd = fs.openSync(fname, "r+");
|
||||
var stat = fs.statSync(fname);
|
||||
var size = stat.size;
|
||||
Item = {name:name, fname:fname, fd:fd, size:size, FillRows:0, CountRows:0, }
|
||||
this.DBMap[name] = Item
|
||||
}
|
||||
return Item;
|
||||
}
|
||||
};
|
||||
var MapCheckProcess = {};
|
||||
var BlockDB = new module.exports();
|
||||
|
||||
function CheckStartOneProcess(Name)
|
||||
{
|
||||
if(global.UpdateMode)
|
||||
return ;
|
||||
if(global.READ_ONLY_DB || MapCheckProcess[Name])
|
||||
return ;
|
||||
MapCheckProcess[Name] = 1;
|
||||
var path = GetDataPath("DB/" + Name);
|
||||
if(fs.existsSync(path))
|
||||
{
|
||||
fs.unlinkSync(path);
|
||||
}
|
||||
try
|
||||
{
|
||||
BlockDB.OpenDBFile(Name);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
ToLog("****** DETECT START ANOTHER PROCESS for: " + Name);
|
||||
ToLogTrace("EXIT");
|
||||
process.exit();
|
||||
}
|
||||
};
|
||||
global.CheckStartOneProcess = CheckStartOneProcess;
|
||||
87
Source/core/geo.js
Normal file
87
Source/core/geo.js
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* @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
|
||||
*/
|
||||
|
||||
var BufIP, fs = require("fs");
|
||||
require("./library.js");
|
||||
var MapNames = {}, FileIp = "./SITE/DB/iplocation.db", FileNames = "./SITE/DB/locationnames.csv", Format = "{Value:uint32,Length:uint32, id:uint32, latitude:uint32, longitude:uint32}",
|
||||
FormatStruct = {};
|
||||
|
||||
function SetGeoLocation(e)
|
||||
{
|
||||
if(!e.ip || !BufIP || !BufIP.length)
|
||||
return !1;
|
||||
var t = IPToUint(e.ip), i = FindItem(BufIP, 20, t);
|
||||
return i && (e.latitude = i.latitude, e.longitude = i.longitude, e.name = MapNames[i.id]), e.Geo = 1, !0;
|
||||
};
|
||||
|
||||
function ReadItem(e,t)
|
||||
{
|
||||
return BufIP.len = e * t, BufLib.Read(BufIP, Format, void 0, FormatStruct);
|
||||
};
|
||||
|
||||
function FindItem(e,t,i)
|
||||
{
|
||||
var n, r = Math.trunc(e.length / t), a = (ReadItem(0, t), ReadItem(r, t), 0), u = r, o = Math.trunc(i * r / 4294967296);
|
||||
r <= o && (o = r - 1), o < a && (o = a);
|
||||
for(var f = 40; 0 < f; )
|
||||
{
|
||||
if(f--, !(n = ReadItem(o, t)))
|
||||
return void ToLog("GEO FindItem - Error read num: " + o);
|
||||
if(n.Value > i)
|
||||
{
|
||||
if(u = o - 1, 0 === (l = o - a))
|
||||
return ;
|
||||
o -= l = Math.trunc((1 + l) / 2);
|
||||
}
|
||||
else
|
||||
if(n.Value < i)
|
||||
{
|
||||
if(n.Value + n.Length >= i)
|
||||
return n;
|
||||
var l;
|
||||
if(a = o + 1, 0 === (l = u - o))
|
||||
return ;
|
||||
o += l = Math.trunc((1 + l) / 2);
|
||||
}
|
||||
else
|
||||
if(n.Value === i)
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
function Init()
|
||||
{
|
||||
if(fs.existsSync(FileIp) && fs.existsSync(FileNames))
|
||||
{
|
||||
BufIP = fs.readFileSync(FileIp);
|
||||
for(var e = fs.readFileSync(FileNames), t = 0; ; )
|
||||
{
|
||||
var i = e.indexOf("\n", t);
|
||||
if(i < 0)
|
||||
break;
|
||||
var n = e.toString("utf-8", t, i - 1);
|
||||
t = i + 1;
|
||||
var r = n.split(","), a = parseInt(r[0]);
|
||||
if(a)
|
||||
{
|
||||
0;
|
||||
var u = r[10];
|
||||
u = (u = u || r[7]) || r[5], MapNames[a] = u;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function IPToUint(e)
|
||||
{
|
||||
var t = e.split(".");
|
||||
return 256 * (256 * (256 * + t[0] + + t[1]) + + t[2]) + + t[3];
|
||||
};
|
||||
global.SetGeoLocation = SetGeoLocation, Init();
|
||||
1987
Source/core/html-server.js
Normal file
1987
Source/core/html-server.js
Normal file
File diff suppressed because it is too large
Load Diff
483
Source/core/library.js
Normal file
483
Source/core/library.js
Normal file
@@ -0,0 +1,483 @@
|
||||
/*
|
||||
* @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
|
||||
*/
|
||||
|
||||
var fs = require('fs');
|
||||
const os = require('os');
|
||||
require("./constant.js");
|
||||
if(global.USE_PARAM_JS)
|
||||
{
|
||||
var PathParams = GetCodePath("../extern-run.js");
|
||||
if(fs.existsSync(PathParams))
|
||||
try
|
||||
{
|
||||
require(PathParams);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
require("./log.js");
|
||||
Number.prototype.toStringZ = function (count)
|
||||
{
|
||||
var strnum = this.toString();
|
||||
if(strnum.length > count)
|
||||
count = strnum.length;
|
||||
else
|
||||
strnum = "0000000000" + strnum;
|
||||
return strnum.substring(strnum.length - count, strnum.length);
|
||||
};
|
||||
String.prototype.right = function (count)
|
||||
{
|
||||
if(this.length > count)
|
||||
return this.substr(this.length - count, count);
|
||||
else
|
||||
return this.substr(0, this.length);
|
||||
};
|
||||
if(fs.existsSync("./lib/bintrees"))
|
||||
global.RBTree = require("../lib/bintrees").RBTree;
|
||||
else
|
||||
global.RBTree = require('bintrees').RBTree;
|
||||
if(fs.existsSync("./lib/ntp-client"))
|
||||
global.ntpClient = require('../lib/ntp-client');
|
||||
else
|
||||
global.ntpClient = require('ntp-client');
|
||||
global.Stun = require('stun');
|
||||
global.ZIP = require("zip");
|
||||
var strOS = os.platform() + "_" + os.arch();
|
||||
if(global.NWMODE)
|
||||
strOS = strOS + "-nw" + global.NWVERSION;
|
||||
if(fs.existsSync("./lib/secp256k1/" + strOS + "/secp256k1.node"))
|
||||
{
|
||||
try
|
||||
{
|
||||
global.secp256k1 = require('../lib/secp256k1/' + strOS + '/secp256k1.node');
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
}
|
||||
}
|
||||
if(!global.secp256k1)
|
||||
{
|
||||
global.secp256k1 = require('secp256k1');
|
||||
}
|
||||
require('../HTML/JS/terahashlib.js');
|
||||
require("./crypto-library");
|
||||
global.BufLib = require("../core/buffer");
|
||||
require('../HTML/JS/sha3.js');
|
||||
require('../HTML/JS/coinlib.js');
|
||||
global.GetCurrentBlockNumByTime = function GetCurrentBlockNumByTime()
|
||||
{
|
||||
var CurTimeNum = GetCurrentTime() - FIRST_TIME_BLOCK;
|
||||
var StartBlockNum = Math.trunc((CurTimeNum + CONSENSUS_PERIOD_TIME) / CONSENSUS_PERIOD_TIME);
|
||||
return StartBlockNum;
|
||||
};
|
||||
global.DelDir = function (Path)
|
||||
{
|
||||
if(Path.substr(Path.length - 1, 1) === "/")
|
||||
Path = Path.substr(0, Path.length - 1);
|
||||
if(fs.existsSync(Path))
|
||||
{
|
||||
var arr = fs.readdirSync(Path);
|
||||
for(var i = 0; i < arr.length; i++)
|
||||
{
|
||||
var name = Path + "/" + arr[i];
|
||||
if(fs.statSync(name).isDirectory())
|
||||
{
|
||||
DelDir(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(name.right(9) == "const.lst")
|
||||
continue;
|
||||
if(name.right(7) == "log.log")
|
||||
continue;
|
||||
fs.unlinkSync(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
global.SliceArr = function (arr,start,end)
|
||||
{
|
||||
var ret = [];
|
||||
for(var i = start; i < end; i++)
|
||||
{
|
||||
ret[i - start] = arr[i];
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
var nRand = Math.floor(123 + Math.random() * 1000);
|
||||
|
||||
function random(max)
|
||||
{
|
||||
return Math.floor(Math.random() * max);
|
||||
};
|
||||
global.random = random;
|
||||
global.AddrLevelArrFromBegin = function (arr1,arr2)
|
||||
{
|
||||
var Level = 0;
|
||||
for(var i = 0; i < arr1.length; i++)
|
||||
{
|
||||
var a1 = arr1[i];
|
||||
var a2 = arr2[i];
|
||||
for(var b = 0; b < 8; b++)
|
||||
{
|
||||
if((a1 & 128) !== (a2 & 128))
|
||||
return Level;
|
||||
a1 = a1 << 1;
|
||||
a2 = a2 << 1;
|
||||
Level++;
|
||||
}
|
||||
}
|
||||
return Level;
|
||||
};
|
||||
global.AddrLevelArr = function (arr1,arr2)
|
||||
{
|
||||
var Level = 0;
|
||||
for(var i = arr1.length - 1; i >= 0; i--)
|
||||
{
|
||||
var a1 = arr1[i];
|
||||
var a2 = arr2[i];
|
||||
for(var b = 0; b < 8; b++)
|
||||
{
|
||||
if((a1 & 1) !== (a2 & 1))
|
||||
return Level;
|
||||
a1 = a1 >> 1;
|
||||
a2 = a2 >> 1;
|
||||
Level++;
|
||||
}
|
||||
}
|
||||
return Level;
|
||||
};
|
||||
global.SaveToFile = function (name,buf)
|
||||
{
|
||||
var fs = require('fs');
|
||||
var file_handle = fs.openSync(name, "w");
|
||||
fs.writeSync(file_handle, buf, 0, buf.length);
|
||||
fs.closeSync(file_handle);
|
||||
};
|
||||
global.LoadParams = function (filename,DefaultValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(fs.existsSync(filename))
|
||||
{
|
||||
var Str = fs.readFileSync(filename);
|
||||
if(Str.length > 0)
|
||||
return JSON.parse(Str);
|
||||
}
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
TO_ERROR_LOG("MAINLIB", 100, "Error in file:" + filename + "\n" + err);
|
||||
}
|
||||
return DefaultValue;
|
||||
};
|
||||
global.SaveParams = function (filename,data)
|
||||
{
|
||||
SaveToFile(filename, Buffer.from(JSON.stringify(data, "", 4)));
|
||||
};
|
||||
global.StartTime = function ()
|
||||
{
|
||||
global.TimeStart = GetCurrentTime();
|
||||
};
|
||||
global.FinishTime = function (Str)
|
||||
{
|
||||
Str = Str || "";
|
||||
var TimeFinish = GetCurrentTime();
|
||||
var delta = TimeFinish - TimeStart;
|
||||
console.log(Str + " time: " + delta + " ms");
|
||||
};
|
||||
global.CompareItemBufFD = function (a,b)
|
||||
{
|
||||
if(a.FD !== b.FD)
|
||||
return a.FD - b.FD;
|
||||
else
|
||||
return a.Position - b.Position;
|
||||
};
|
||||
global.CompareArr33 = function (a,b)
|
||||
{
|
||||
for(var i = 0; i < 33; i++)
|
||||
{
|
||||
if(a[i] !== b[i])
|
||||
return a[i] - b[i];
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
global.CompareItemHashSimple = function (a,b)
|
||||
{
|
||||
if(a.hash < b.hash)
|
||||
return - 1;
|
||||
else
|
||||
if(a.hash > b.hash)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
};
|
||||
global.CompareItemHash = function (a,b)
|
||||
{
|
||||
var hasha = a.hash;
|
||||
var hashb = b.hash;
|
||||
for(var i = 0; i < hasha.length; i++)
|
||||
{
|
||||
if(hasha[i] !== hashb[i])
|
||||
return hasha[i] - hashb[i];
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
global.CompareItemHash32 = function (a,b)
|
||||
{
|
||||
var hasha = a.hash;
|
||||
var hashb = b.hash;
|
||||
for(var i = 0; i < 32; i++)
|
||||
{
|
||||
if(hasha[i] !== hashb[i])
|
||||
return hasha[i] - hashb[i];
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
global.CompareItemHASH32 = function (a,b)
|
||||
{
|
||||
var hasha = a.HASH;
|
||||
var hashb = b.HASH;
|
||||
for(var i = 0; i < 32; i++)
|
||||
{
|
||||
if(hasha[i] !== hashb[i])
|
||||
return hasha[i] - hashb[i];
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
global.CompareItemHash33 = function (a,b)
|
||||
{
|
||||
var hasha = a.hash;
|
||||
var hashb = b.hash;
|
||||
for(var i = 0; i < 33; i++)
|
||||
{
|
||||
if(hasha[i] !== hashb[i])
|
||||
return hasha[i] - hashb[i];
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
global.CompareItemHashPow = function (a,b)
|
||||
{
|
||||
return CompareArr(a.HashPow, b.HashPow);
|
||||
};
|
||||
global.CompareItemTimePow = function (a,b)
|
||||
{
|
||||
if(b.TimePow !== a.TimePow)
|
||||
return b.TimePow - a.TimePow;
|
||||
else
|
||||
return CompareArr(a.HashPow, b.HashPow);
|
||||
};
|
||||
global.LOAD_CONST = function ()
|
||||
{
|
||||
var Count = 0;
|
||||
var constants = LoadParams(GetDataPath("const.lst"), {});
|
||||
if(constants)
|
||||
{
|
||||
for(var i = 0; i < CONST_NAME_ARR.length; i++)
|
||||
{
|
||||
var key = CONST_NAME_ARR[i];
|
||||
if(constants[key] !== undefined)
|
||||
{
|
||||
Count++;
|
||||
global[key] = constants[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
return Count;
|
||||
};
|
||||
var WasStartSaveConst = false;
|
||||
|
||||
function SaveConst()
|
||||
{
|
||||
var constants = {};
|
||||
for(var i = 0; i < CONST_NAME_ARR.length; i++)
|
||||
{
|
||||
var key = CONST_NAME_ARR[i];
|
||||
if(global[key] !== undefined)
|
||||
constants[key] = global[key];
|
||||
}
|
||||
SaveParams(GetDataPath("const.lst"), constants);
|
||||
WasStartSaveConst = false;
|
||||
};
|
||||
global.SAVE_CONST = function (bForce)
|
||||
{
|
||||
if(bForce)
|
||||
{
|
||||
SaveConst();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!WasStartSaveConst)
|
||||
setTimeout(SaveConst, 10 * 1000);
|
||||
WasStartSaveConst = true;
|
||||
}
|
||||
};
|
||||
|
||||
function CheckGlobalTime()
|
||||
{
|
||||
ntpClient.getNetworkTime("pool.ntp.org", 123, function (err,NetTime)
|
||||
{
|
||||
if(err)
|
||||
{
|
||||
TO_ERROR_LOG("MAINLIB", 110, err);
|
||||
return ;
|
||||
}
|
||||
var curTime = new Date;
|
||||
global.DELTA_CURRENT_TIME = NetTime - curTime;
|
||||
if(isNaN(global.DELTA_CURRENT_TIME) || typeof global.DELTA_CURRENT_TIME !== "number")
|
||||
global.DELTA_CURRENT_TIME = 0;
|
||||
else
|
||||
if(Math.abs(global.DELTA_CURRENT_TIME) > 24 * 3600 * 1000)
|
||||
global.DELTA_CURRENT_TIME = 0;
|
||||
ToLog("Get global time: " + NetTime);
|
||||
SAVE_CONST();
|
||||
});
|
||||
SAVE_CONST();
|
||||
};
|
||||
global.CheckGlobalTime = CheckGlobalTime;
|
||||
global.GetDeltaCurrentTime = function ()
|
||||
{
|
||||
if(isNaN(global.DELTA_CURRENT_TIME) || typeof global.DELTA_CURRENT_TIME !== "number")
|
||||
global.DELTA_CURRENT_TIME = 0;
|
||||
return global.DELTA_CURRENT_TIME;
|
||||
};
|
||||
global.GetStrTimeUTC = function (now)
|
||||
{
|
||||
if(!global.GetCurrentTime)
|
||||
return ":::";
|
||||
if(!now)
|
||||
now = GetCurrentTime();
|
||||
var Str = "" + now.getUTCDate();
|
||||
Str = Str + "." + (1 + now.getUTCMonth());
|
||||
Str = Str + "." + now.getUTCFullYear();
|
||||
Str = Str + " " + now.getUTCHours();
|
||||
Str = Str + ":" + now.getUTCMinutes();
|
||||
Str = Str + ":" + now.getUTCSeconds();
|
||||
return Str;
|
||||
};
|
||||
global.GetStrOnlyTimeUTC = function (now)
|
||||
{
|
||||
if(!global.GetCurrentTime)
|
||||
return ":::";
|
||||
if(!now)
|
||||
now = GetCurrentTime();
|
||||
var Str;
|
||||
Str = "" + now.getUTCHours().toStringZ(2);
|
||||
Str = Str + ":" + now.getUTCMinutes().toStringZ(2);
|
||||
Str = Str + ":" + now.getUTCSeconds().toStringZ(2);
|
||||
return Str;
|
||||
};
|
||||
|
||||
function GetSecFromStrTime(Str)
|
||||
{
|
||||
var arr = Str.split(":");
|
||||
var Mult = 3600;
|
||||
var Sum = 0;
|
||||
for(var i = 0; i < arr.length; i++)
|
||||
{
|
||||
Sum += Mult * parseInt(arr[i]);
|
||||
Mult = Mult / 60;
|
||||
}
|
||||
return Sum;
|
||||
};
|
||||
global.GetSecFromStrTime = GetSecFromStrTime;
|
||||
global.GetCurrentTime = function (Delta_Time)
|
||||
{
|
||||
if(Delta_Time === undefined)
|
||||
Delta_Time = GetDeltaCurrentTime();
|
||||
var curTime = new Date;
|
||||
var Time = new Date(curTime - ( - Delta_Time));
|
||||
return Time;
|
||||
};
|
||||
|
||||
function DateFromBlock(BlockNum)
|
||||
{
|
||||
var Str;
|
||||
var now = new Date(FIRST_TIME_BLOCK + BlockNum * 1000);
|
||||
Str = now.toISOString();
|
||||
Str = Str.substr(0, Str.indexOf("."));
|
||||
Str = Str.replace("T", " ");
|
||||
return Str;
|
||||
};
|
||||
global.DateFromBlock = DateFromBlock;
|
||||
var code_base = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0402\u0403\u201a\u0453\u201e\u2026\u2020\u2021\u20ac\u2030\u0409\u2039\u040a\u040c\u040b\u040f\u0452\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffd\u2122\u0459\u203a\u045a\u045c\u045b\u045f\xa0\u040e\u045e\u0408\xa4\u0490\xa6\xa7\u0401\xa9\u0404\xab\xac\xad\xae\u0407\xb0\xb1\u0406\u0456\u0491\xb5\xb6\xb7\u0451\u2116\u0454\xbb\u0458\u0405\u0455\u0457\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f';
|
||||
global.NormalizeName = function (Name)
|
||||
{
|
||||
var Str = "";
|
||||
for(var i = 0; i < Name.length; i++)
|
||||
{
|
||||
var code = Name.charCodeAt(i);
|
||||
if(code >= 32)
|
||||
Str += code_base.charAt(code - 32);
|
||||
}
|
||||
return Str;
|
||||
};
|
||||
var glEvalMap = {};
|
||||
|
||||
function CreateEval(formula,StrParams)
|
||||
{
|
||||
var Ret = glEvalMap[formula];
|
||||
if(!Ret)
|
||||
{
|
||||
eval("function M(" + StrParams + "){return " + formula + "}; Ret=M;");
|
||||
glEvalMap[formula] = Ret;
|
||||
}
|
||||
return Ret;
|
||||
};
|
||||
global.CreateEval = CreateEval;
|
||||
var CPU_Count = os.cpus().length;
|
||||
|
||||
function GetCountMiningCPU()
|
||||
{
|
||||
if(global.COUNT_MINING_CPU)
|
||||
return global.COUNT_MINING_CPU;
|
||||
else
|
||||
{
|
||||
return CPU_Count - 1;
|
||||
}
|
||||
};
|
||||
global.GetCountMiningCPU = GetCountMiningCPU;
|
||||
var AddTrMap = {};
|
||||
AddTrMap[ - 6] = "Inner node error";
|
||||
AddTrMap[ - 5] = "Bad block num";
|
||||
AddTrMap[ - 4] = "Bad type transaction";
|
||||
AddTrMap[ - 3] = "Bad time";
|
||||
AddTrMap[ - 2] = "Bad PoW";
|
||||
AddTrMap[ - 1] = "Bad length";
|
||||
AddTrMap[0] = "Not add";
|
||||
AddTrMap[1] = "OK";
|
||||
AddTrMap[2] = "Update OK";
|
||||
AddTrMap[3] = "Was send";
|
||||
AddTrMap[4] = "Added to timer";
|
||||
global.AddTrMap = AddTrMap;
|
||||
|
||||
function GrayConnect()
|
||||
{
|
||||
if(global.NET_WORK_MODE && !NET_WORK_MODE.UseDirectIP)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
};
|
||||
global.GrayConnect = GrayConnect;
|
||||
var ResConst = LOAD_CONST();
|
||||
if(global.START_SERVER)
|
||||
{
|
||||
if(!ResConst)
|
||||
{
|
||||
CheckGlobalTime();
|
||||
}
|
||||
else
|
||||
if(global.CHECK_GLOBAL_TIME)
|
||||
{
|
||||
CheckGlobalTime();
|
||||
}
|
||||
}
|
||||
38
Source/core/log-strict.js
Normal file
38
Source/core/log-strict.js
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* @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
|
||||
*/
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
function CheckSizeLogFile(file_name,file_name_prev)
|
||||
{
|
||||
"use strict";
|
||||
let FILE_NAME_LOG = file_name;
|
||||
let FILE_NAME_LOG_PREV = file_name_prev;
|
||||
setInterval(function ()
|
||||
{
|
||||
try
|
||||
{
|
||||
var stat = fs.statSync(FILE_NAME_LOG);
|
||||
if(stat.size > MAX_SIZE_LOG)
|
||||
{
|
||||
if(fs.existsSync(FILE_NAME_LOG_PREV))
|
||||
{
|
||||
fs.unlinkSync(FILE_NAME_LOG_PREV);
|
||||
}
|
||||
fs.renameSync(FILE_NAME_LOG, FILE_NAME_LOG_PREV);
|
||||
ToLog("truncate logfile ok");
|
||||
}
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
}
|
||||
}, 60000);
|
||||
};
|
||||
global.CheckSizeLogFile = CheckSizeLogFile;
|
||||
267
Source/core/log.js
Normal file
267
Source/core/log.js
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* @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
|
||||
*/
|
||||
|
||||
require("./constant.js");
|
||||
var fs = require("fs");
|
||||
require("./log-strict.js");
|
||||
var file_name_info = GetDataPath("info.log"), file_name_infoPrev = GetDataPath("info-prev.log");
|
||||
CheckSizeLogFile(file_name_info, file_name_infoPrev);
|
||||
var file_name_log = GetDataPath("log.log"), file_name_logPrev = GetDataPath("log-prev.log");
|
||||
CheckSizeLogFile(file_name_log, file_name_logPrev);
|
||||
var file_name_log_web = GetDataPath("web.log"), file_name_log_webPrev = GetDataPath("web-prev.log");
|
||||
CheckSizeLogFile(file_name_log_web, file_name_log_webPrev);
|
||||
var file_name_error = GetDataPath("err.log"), file_name_errorPrev = GetDataPath("err-prev.log");
|
||||
CheckSizeLogFile(file_name_error, file_name_errorPrev);
|
||||
var StartStatTime, file_name_error_tx = GetDataPath("err-tx.log"), file_name_error_txPrev = GetDataPath("err-tx-prev.log");
|
||||
|
||||
function ToLogFile(e,t,r)
|
||||
{
|
||||
t instanceof Error && (t = t.message + "\n" + t.stack), global.START_SERVER || (t = global.PROCESS_NAME + ": " + t), "MAIN" !== global.PROCESS_NAME && process.send ? process.send({cmd:"log",
|
||||
message:t}) : (console.log(START_PORT_NUMBER + ": " + GetStrOnlyTime() + ": " + t), r || SaveToLogFileSync(e, t));
|
||||
};
|
||||
|
||||
function ToLogClient(e,t,r)
|
||||
{
|
||||
e && (ToLogFile(file_name_log, e), t = t || "", ArrLogClient.push({text:GetStrOnlyTime() + " " + e, key:t, final:r}), 13 < ArrLogClient.length && ArrLogClient.shift());
|
||||
};
|
||||
CheckSizeLogFile(file_name_error_tx, file_name_error_txPrev), global.ToLog = function (e,t)
|
||||
{
|
||||
void 0 === t && (t = 1), t && t > global.LOG_LEVEL || (global.ALL_LOG_TO_CLIENT ? ToLogClient(e, void 0, void 0) : ToLogFile(file_name_log,
|
||||
e));
|
||||
}, global.WEB_LOG = 0, global.ToLogWeb = function (e)
|
||||
{
|
||||
global.WEB_LOG && SaveToLogFileSync(file_name_log_web, e);
|
||||
}, global.SmallAddr = function (e)
|
||||
{
|
||||
return e.substr(0, 5);
|
||||
}, global.ToErrorTrace = function (e)
|
||||
{
|
||||
ToError(e + ":" + (new Error).stack);
|
||||
}, global.ToLogTrace = function (e)
|
||||
{
|
||||
ToErrorTrace(e);
|
||||
}, global.ToInfo = function (e)
|
||||
{
|
||||
ToLogFile(file_name_info, e, 1);
|
||||
}, global.ToError = function (e)
|
||||
{
|
||||
ToLogFile(file_name_error, e);
|
||||
}, global.ToErrorTx = function (e)
|
||||
{
|
||||
SaveToLogFileSync(file_name_error_tx, e), ToLog(e);
|
||||
}, global.ArrLogClient = [], global.ToLogClient = ToLogClient, global.ToLogClient0 = ToLogClient;
|
||||
var CONTEXT_STATS = {Total:{}, Interval:[]}, CONTEXT_ERRORS = {Total:{}, Interval:[]}, CurStatIndex = 0;
|
||||
|
||||
function GetCurrentStatIndex()
|
||||
{
|
||||
var e = 2 * MAX_STAT_PERIOD + 2;
|
||||
return CurStatIndex % e;
|
||||
};
|
||||
|
||||
function ResizeArrMax(e)
|
||||
{
|
||||
for(var t = [], r = Math.trunc(e.length / 2), o = 0; o < r; o++)
|
||||
t[o] = Math.max(e[2 * o], e[2 * o + 1]);
|
||||
return t;
|
||||
};
|
||||
|
||||
function ResizeArrAvg(e)
|
||||
{
|
||||
for(var t = [], r = Math.trunc(e.length / 2), o = 0; o < r; o++)
|
||||
t[o] = (e[2 * o] + e[2 * o + 1]) / 2;
|
||||
return t;
|
||||
};
|
||||
|
||||
function ResizeArr(e)
|
||||
{
|
||||
for(var t = [], r = Math.trunc(e.length / 2), o = 0; o < r; o++)
|
||||
t[o] = e[2 * o];
|
||||
return t;
|
||||
};
|
||||
|
||||
function GetDiagramData(e,t)
|
||||
{
|
||||
var r, o = 2 * MAX_STAT_PERIOD + 2;
|
||||
r = "MAX:" === t.substr(0, 4);
|
||||
for(var n, a = MAX_STAT_PERIOD, l = (GetCurrentStatIndex() - a + o) % o, i = (e.Total, []), T = void 0, g = l; g < l + a; g++)
|
||||
{
|
||||
var S = g % o;
|
||||
if(n = e.Interval[S])
|
||||
{
|
||||
var _ = n[t];
|
||||
void 0 !== _ ? r ? i.push(_) : (void 0 !== T ? i.push(_ - T) : i.push(_), T = _) : i.push(0);
|
||||
}
|
||||
}
|
||||
return i;
|
||||
};
|
||||
|
||||
function CalcInterval(e,t,r)
|
||||
{
|
||||
for(var o, n = 2 * MAX_STAT_PERIOD + 2, a = {}, l = (t - r + n) % n, i = e.Total, T = l; T < l + r; T++)
|
||||
{
|
||||
var g = T % n;
|
||||
if(o = e.Interval[g])
|
||||
break;
|
||||
}
|
||||
if(o)
|
||||
for(var S in i)
|
||||
"MAX:" === S.substr(0, 4) ? a[S] = 0 : void 0 === o[S] ? a[S] = i[S] : a[S] = i[S] - o[S];
|
||||
return a;
|
||||
};
|
||||
|
||||
function AddToStatContext(e,t,r)
|
||||
{
|
||||
void 0 === r && (r = 1);
|
||||
var o = e.Total[t];
|
||||
o = o || 0, "MAX:" === t.substr(0, 4) ? o = Math.max(o, r) : o += r, e.Total[t] = o, StartStatTime = StartStatTime || GetCurrentTime(0);
|
||||
};
|
||||
|
||||
function CopyStatInterval(e,t)
|
||||
{
|
||||
var r = e.Interval[t];
|
||||
r || (r = {}, e.Interval[t] = r);
|
||||
var o = e.Total;
|
||||
for(var n in o)
|
||||
r[n] = o[n], "MAX:" === n.substr(0, 4) && (o[n] = 0);
|
||||
};
|
||||
|
||||
function SaveToLogFileAsync(e,o)
|
||||
{
|
||||
fs.open(e, "a", void 0, function (e,r)
|
||||
{
|
||||
if(e)
|
||||
console.log("Ошибка открытия лог-файла ошибок");
|
||||
else
|
||||
{
|
||||
var t = GetStrTime() + " : " + o + "\r\n";
|
||||
fs.write(r, t, null, "utf8", function (e,t)
|
||||
{
|
||||
e ? console.log("Ошибка записи в лог-файл ошибок!") : fs.close(r, function (e)
|
||||
{
|
||||
e && console.log(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function SaveToLogFileSync(e,t)
|
||||
{
|
||||
try
|
||||
{
|
||||
var r = GetStrTime() + " : " + t + "\r\n", o = fs.openSync(e, "a");
|
||||
fs.writeSync(o, r, null, "utf8"), fs.closeSync(o);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
console.log(e.message);
|
||||
}
|
||||
};
|
||||
global.PrepareStatEverySecond = function ()
|
||||
{
|
||||
CurStatIndex++;
|
||||
var e = GetCurrentStatIndex();
|
||||
CopyStatInterval(CONTEXT_STATS, e), CopyStatInterval(CONTEXT_ERRORS, e);
|
||||
}, global.TO_ERROR_LOG = function (e,t,r,o,n,a)
|
||||
{
|
||||
r instanceof Error && (r = r.message + "\n"), "rinfo" === o ? r += " from: " + n.address + ":" + n.port : "node" === o && (r += " from: " + n.ip + ":" + n.port);
|
||||
var l = e + ":" + t;
|
||||
ToError(" ==ERROR== " + l + " " + r), AddToStatContext(CONTEXT_ERRORS, l), ADD_TO_STAT("ERRORS");
|
||||
}, global.HASH_RATE = 0, global.ADD_HASH_RATE = function (e)
|
||||
{
|
||||
e /= 1e6, global.HASH_RATE += e, ADD_TO_STAT("HASHRATE", e);
|
||||
}, global.GET_STAT = function (e)
|
||||
{
|
||||
var t = CONTEXT_STATS.Total[e];
|
||||
return t = t || 0;
|
||||
}, global.ADD_TO_STAT_TIME = function (e,t,r)
|
||||
{
|
||||
if(global.STAT_MODE)
|
||||
{
|
||||
if(r && 2 !== global.STAT_MODE)
|
||||
return ;
|
||||
var o = process.hrtime(t), n = 1e3 * o[0] + o[1] / 1e6;
|
||||
ADD_TO_STAT(e, n);
|
||||
}
|
||||
}, global.ADD_TO_STAT = function (e,t,r)
|
||||
{
|
||||
if(global.STAT_MODE)
|
||||
{
|
||||
if(r && 2 !== global.STAT_MODE)
|
||||
return ;
|
||||
AddToStatContext(CONTEXT_STATS, e, t);
|
||||
}
|
||||
}, global.GET_STATDIAGRAMS = function (e)
|
||||
{
|
||||
GetCurrentTime();
|
||||
var t = GetCurrentStatIndex();
|
||||
if(!e || !e.length)
|
||||
return [];
|
||||
for(var r = [], o = 0; o < e.length; o++)
|
||||
{
|
||||
var n = e[o], a = GetDiagramData(CONTEXT_STATS, n);
|
||||
r.push({name:n, maxindex:t, arr:a, starttime:StartStatTime - 0, steptime:1});
|
||||
}
|
||||
var l = void 0;
|
||||
for(o = 0; o < r.length; o++)
|
||||
{
|
||||
0 < (T = r[o].arr).length && (void 0 === l || T.length < l) && (l = T.length);
|
||||
}
|
||||
for(o = 0; o < r.length; o++)
|
||||
{
|
||||
var i = r[o], T = i.arr;
|
||||
l && T.length > l && (T = T.slice(T.length - l)), l && 0 <= ",POWER_MY_WIN,POWER_BLOCKCHAIN,".indexOf("," + i.name + ",") && (T = SERVER.GetStatBlockchain(i.name,
|
||||
l));
|
||||
for(var g = 0, S = 0; S < T.length; S++)
|
||||
T[S] && (g += T[S]);
|
||||
0 < T.length && (g /= T.length);
|
||||
var _ = 1;
|
||||
if("MAX:" === i.name.substr(0, 4))
|
||||
for(; 500 <= T.length; )
|
||||
T = ResizeArrMax(T), _ *= 2;
|
||||
else
|
||||
for(; 500 <= T.length; )
|
||||
T = ResizeArrAvg(T), _ *= 2;
|
||||
i.AvgValue = g, i.steptime = _, i.arr = T.slice(1);
|
||||
}
|
||||
return r;
|
||||
}, global.GET_STATS = function (e)
|
||||
{
|
||||
var t = GetCurrentTime(), r = GetCurrentStatIndex();
|
||||
return {stats:{Counter:CONTEXT_STATS.Total, Counter10S:CalcInterval(CONTEXT_STATS, r, 10), Counter10M:CalcInterval(CONTEXT_STATS,
|
||||
r, 600)}, errors:{Counter:CONTEXT_ERRORS.Total, Counter10S:CalcInterval(CONTEXT_ERRORS, r, 10), Counter10M:CalcInterval(CONTEXT_ERRORS,
|
||||
r, 600)}, period:(t - StartStatTime) / 1e3, Confirmation:[]};
|
||||
}, global.StartCommonStat = function ()
|
||||
{
|
||||
for(var e in CONTEXT_STATS.Total)
|
||||
return ;
|
||||
ClearCommonStat();
|
||||
}, global.ClearCommonStat = function ()
|
||||
{
|
||||
StartStatTime = void (CurStatIndex = 0), CONTEXT_STATS = {Total:{}, Interval:[]}, CONTEXT_ERRORS = {Total:{}, Interval:[]},
|
||||
global.HASH_RATE = 0, SERVER.ClearStat();
|
||||
}, global.ResizeArrAvg = ResizeArrAvg, global.ResizeArrMax = ResizeArrMax, DEBUG_MODE ? global.TO_DEBUG_LOG = function (e,t,r,o)
|
||||
{
|
||||
DEBUG_MODE && ("rinfo" === t && (e += " from: " + r.address + ":" + r.port + " - " + o.length), ToLog(e));
|
||||
} : global.TO_DEBUG_LOG = function (e,t,r,o)
|
||||
{
|
||||
}, global.GetStrOnlyTime = function (e)
|
||||
{
|
||||
if(!global.GetCurrentTime)
|
||||
return ":::";
|
||||
var t = "" + (e = e || GetCurrentTime()).getHours().toStringZ(2);
|
||||
return t = (t = (t = t + ":" + e.getMinutes().toStringZ(2)) + ":" + e.getSeconds().toStringZ(2)) + "." + e.getMilliseconds().toStringZ(3);
|
||||
}, global.GetStrTime = function (e)
|
||||
{
|
||||
if(!global.GetCurrentTime)
|
||||
return ":::";
|
||||
var t = "" + (e = e || GetCurrentTime()).getDate().toStringZ(2);
|
||||
return t = (t = (t = (t = (t = (t = t + "." + (1 + e.getMonth()).toStringZ(2)) + "." + e.getFullYear()) + " " + e.getHours().toStringZ(2)) + ":" + e.getMinutes().toStringZ(2)) + ":" + e.getSeconds().toStringZ(2)) + "." + e.getMilliseconds().toStringZ(3);
|
||||
};
|
||||
614
Source/core/node.js
Normal file
614
Source/core/node.js
Normal file
@@ -0,0 +1,614 @@
|
||||
/*
|
||||
* @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";
|
||||
require("./library.js");
|
||||
const net = require("net");
|
||||
var ConnectIDCount = 1;
|
||||
module.exports = class CNode
|
||||
{
|
||||
constructor(addrStr, ip, port)
|
||||
{
|
||||
this.addrStr = addrStr
|
||||
this.ip = ip.trim()
|
||||
this.port = port
|
||||
this.StartFindList = 0
|
||||
this.WhiteConnect = 0
|
||||
this.GrayConnect = 0
|
||||
this.POW = 0
|
||||
this.FirstTime = 0
|
||||
this.FirstTimeStr = ""
|
||||
this.LastTime = 0
|
||||
this.LastTimeError = 0
|
||||
this.LastTimeTransfer = 0
|
||||
this.FromIP = undefined
|
||||
this.FromPort = undefined
|
||||
this.Active = false
|
||||
this.Hot = false
|
||||
this.CanHot = false
|
||||
this.CountChildConnect = 0
|
||||
this.BlockProcessCount = 0
|
||||
this.VersionOK = false
|
||||
this.VersionNum = 0
|
||||
this.Delete = 0
|
||||
this.DeltaBan = 300
|
||||
this.Name = ""
|
||||
this.Info = ""
|
||||
this.PrevInfo = ""
|
||||
this.StartTimeHot = 0
|
||||
this.NextHotDelta = 1000
|
||||
this.ResetNode()
|
||||
}
|
||||
ResetNode()
|
||||
{
|
||||
this.LastTimeGetNode = 0
|
||||
this.DeltaGlobTime = 0
|
||||
this.CountDeltaTime = 0
|
||||
this.DeltaTime = 1000
|
||||
this.SumDeltaTime = 0
|
||||
this.TransferCount = 0
|
||||
this.StopGetBlock = 0
|
||||
this.LevelCount = 0
|
||||
this.LevelEnum = 100
|
||||
this.TimeMap = {}
|
||||
this.bInit = 1
|
||||
this.INFO = {}
|
||||
this.DoubleConnectCount = 0
|
||||
this.StartTimeConnect = 0
|
||||
this.NextConnectDelta = 1000
|
||||
this.StartTimeGetNodes = 0
|
||||
this.NextGetNodesDelta = 1000
|
||||
this.PingStart = 0
|
||||
this.NextPing = MIN_PERIOD_PING
|
||||
this.SendBlockArr = []
|
||||
this.LoadBlockArr = []
|
||||
this.SendBlockCount = 0
|
||||
this.LoadBlockCount = 0
|
||||
this.SendBlockCountAll = 0
|
||||
this.LoadBlockCountAll = 0
|
||||
this.WantHardTrafficArr = []
|
||||
this.WantHardTraffic = 0
|
||||
this.CanHardTraffic = 0
|
||||
this.BufWriteLength = 0
|
||||
this.BufWrite = Buffer.alloc(0)
|
||||
this.SendPacket = new RBTree(function (a,b)
|
||||
{
|
||||
return b.PacketNum - a.PacketNum;
|
||||
})
|
||||
this.ConnectCount = 0
|
||||
this.TrafficArr = []
|
||||
this.SendTrafficCurrent = 0
|
||||
this.SendTrafficLimit = 0
|
||||
this.ErrCount = 0
|
||||
this.ErrCountAll = 0
|
||||
var Prioritet = this.BlockProcessCount;
|
||||
SERVER.SetNodePrioritet(this, Prioritet)
|
||||
this.SendPacketNum = 0
|
||||
}
|
||||
ConnectStatus()
|
||||
{
|
||||
if(this.Socket)
|
||||
return GetSocketStatus(this.Socket);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
CreateConnect()
|
||||
{
|
||||
delete SERVER.BAN_IP[this.ip]
|
||||
let NODE = this;
|
||||
if(NODE.ConnectStatus())
|
||||
{
|
||||
if(NODE.ConnectStatus() === 100)
|
||||
SERVER.AddNodeToActive(NODE)
|
||||
return ;
|
||||
}
|
||||
AddNodeInfo(NODE, "===CreateConnect===")
|
||||
CloseSocket(NODE.Socket, "CreateConnect")
|
||||
NODE.SocketStart = Date.now()
|
||||
NODE.Socket = net.createConnection(NODE.port, NODE.ip, function ()
|
||||
{
|
||||
if(NODE.Socket)
|
||||
{
|
||||
socketInit(NODE.Socket, "s")
|
||||
AddNodeInfo(NODE, "OK connected *" + NODE.Socket.ConnectID)
|
||||
NODE.Socket.ConnectToServer = true
|
||||
SetSocketStatus(NODE.Socket, 2)
|
||||
}
|
||||
})
|
||||
SetSocketStatus(NODE.Socket, 1)
|
||||
NODE.Socket.Node = NODE
|
||||
NODE.Socket.ConnectID = "~C" + ConnectIDCount
|
||||
ConnectIDCount++
|
||||
this.SetEventsProcessing(NODE.Socket, 0)
|
||||
}
|
||||
CreateReconnection()
|
||||
{
|
||||
let NODE = this;
|
||||
AddNodeInfo(NODE, "===CreateReconnection===")
|
||||
CloseSocket(NODE.Socket2, "CreateReconnection")
|
||||
NODE.SocketStart = Date.now()
|
||||
NODE.Socket2 = net.createConnection(NODE.port, NODE.ip, function ()
|
||||
{
|
||||
if(NODE.Socket2)
|
||||
{
|
||||
socketInit(NODE.Socket2, "s")
|
||||
AddNodeInfo(NODE, "OK Reconnected *" + NODE.Socket2.ConnectID)
|
||||
NODE.Socket2.ConnectToServer = true
|
||||
SetSocketStatus(NODE.Socket2, 2)
|
||||
}
|
||||
})
|
||||
SetSocketStatus(NODE.Socket2, 1)
|
||||
NODE.Socket2.Node = NODE
|
||||
NODE.Socket2.ConnectID = "~R" + ConnectIDCount
|
||||
ConnectIDCount++
|
||||
this.SetEventsProcessing(NODE.Socket2, 1)
|
||||
}
|
||||
SwapSockets()
|
||||
{
|
||||
if(!this.Socket2)
|
||||
return ;
|
||||
var SocketOld = this.Socket;
|
||||
this.Socket = this.Socket2
|
||||
this.Socket2 = undefined
|
||||
this.Socket.Node = this
|
||||
SetSocketStatus(this.Socket, 100)
|
||||
this.Socket.Buf = SocketOld.Buf
|
||||
SERVER.LoadBufSocketList.remove(SocketOld)
|
||||
SERVER.LoadBufSocketList.insert(this.Socket)
|
||||
SocketOld.Buf = undefined
|
||||
SocketOld.WasClose = 1
|
||||
SocketOld.Node = undefined
|
||||
this.ErrCount = 0
|
||||
}
|
||||
SetEventsProcessing(Socket, Reconnection)
|
||||
{
|
||||
let SOCKET = Socket;
|
||||
let NODE = this;
|
||||
let RECONNECTION = Reconnection;
|
||||
SOCKET.on('data', function (data)
|
||||
{
|
||||
if(Socket.WasClose)
|
||||
return ;
|
||||
if(GetSocketStatus(SOCKET) === 2)
|
||||
{
|
||||
SetSocketStatus(SOCKET, 3)
|
||||
var Buf = SERVER.GetDataFromBuf(data);
|
||||
if(Buf)
|
||||
{
|
||||
var Res = NODE.SendPOWFromClientToServer(SOCKET, Buf.Data);
|
||||
if(Res)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
}
|
||||
CloseSocket(SOCKET, Buf ? "Method=" + Buf.Method : "=CLIENT ON DATA=")
|
||||
}
|
||||
else
|
||||
if(GetSocketStatus(SOCKET) === 3)
|
||||
{
|
||||
var Buf = SERVER.GetDataFromBuf(data);
|
||||
if(Buf)
|
||||
{
|
||||
var Str = Buf.Data;
|
||||
if(Str && Str.substr(0, 24) === "WAIT_CONNECT_FROM_SERVER")
|
||||
{
|
||||
AddNodeInfo(NODE, "2. CLIENT OK POW")
|
||||
CloseSocket(SOCKET, "WAIT_CONNECT_FROM_SERVER")
|
||||
NODE.WaitConnectFromServer = 1
|
||||
NODE.WaitConnectIP = NODE.ip
|
||||
try
|
||||
{
|
||||
NODE.SecretForReconnect = GetArrFromHex(Str.substr(25))
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
NODE.SecretForReconnect = []
|
||||
ToLog(e)
|
||||
}
|
||||
}
|
||||
else
|
||||
if(Str === "OK")
|
||||
{
|
||||
NODE.NextConnectDelta = 1000
|
||||
SetSocketStatus(SOCKET, 100)
|
||||
AddNodeInfo(NODE, "4. CLIENT OK CONNECT")
|
||||
if(RECONNECTION)
|
||||
{
|
||||
if(NODE.Socket)
|
||||
SetSocketStatus(NODE.Socket, 200)
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!NODE.Active)
|
||||
SERVER.AddNodeToActive(NODE)
|
||||
}
|
||||
return ;
|
||||
}
|
||||
else
|
||||
if(Str === "SELF")
|
||||
{
|
||||
NODE.Self = 1
|
||||
}
|
||||
else
|
||||
if(Str === "DOUBLE")
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
AddNodeInfo(NODE, "ERROR:" + Str)
|
||||
}
|
||||
}
|
||||
CloseSocket(SOCKET, Buf ? "Method=" + Buf.Method + ":" + Str : "=CLIENT ON DATA=")
|
||||
}
|
||||
else
|
||||
{
|
||||
socketRead(Socket, data)
|
||||
SERVER.OnGetFromTCP(NODE, Socket, data)
|
||||
}
|
||||
})
|
||||
SOCKET.on('end', function ()
|
||||
{
|
||||
if(GetSocketStatus(SOCKET))
|
||||
AddNodeInfo(NODE, "Get socket end *" + SOCKET.ConnectID + " Stat: " + SocketStatistic(SOCKET))
|
||||
if(GetSocketStatus(SOCKET) === 200)
|
||||
{
|
||||
NODE.SwapSockets()
|
||||
SOCKET.WasClose = 1
|
||||
}
|
||||
})
|
||||
SOCKET.on('close', function (err)
|
||||
{
|
||||
if(SOCKET.ConnectID && GetSocketStatus(SOCKET))
|
||||
AddNodeInfo(NODE, "Get socket close *" + SOCKET.ConnectID + " Stat: " + SocketStatistic(SOCKET))
|
||||
if(!SOCKET.WasClose)
|
||||
{
|
||||
if(GetSocketStatus(SOCKET) >= 2)
|
||||
{
|
||||
CloseSocket(SOCKET, "GET CLOSE")
|
||||
}
|
||||
}
|
||||
SetSocketStatus(SOCKET, 0)
|
||||
})
|
||||
SOCKET.on('error', function (err)
|
||||
{
|
||||
if(GetSocketStatus(SOCKET) >= 2)
|
||||
{
|
||||
SERVER.AddCheckErrCount(NODE, 1, "ERR##1 : socket")
|
||||
ADD_TO_STAT("ERRORS")
|
||||
}
|
||||
})
|
||||
}
|
||||
SendPOWFromClientToServer(Socket, data)
|
||||
{
|
||||
var Node = this;
|
||||
if(Node.ReconnectFromServer)
|
||||
{
|
||||
Node.ReconnectFromServer = 0
|
||||
var Info = this.GetPOWClientData(0);
|
||||
Info.Reconnect = 1
|
||||
Info.SecretForReconnect = Node.SecretForReconnect
|
||||
var BufWrite = BufLib.GetBufferFromObject(Info, FORMAT_POW_TO_SERVER, 1200, {});
|
||||
var BufAll = SERVER.GetBufFromData("POW_CONNECT7", BufWrite, 1);
|
||||
Socket.write(BufAll)
|
||||
return 1;
|
||||
}
|
||||
try
|
||||
{
|
||||
var Buf = BufLib.GetObjectFromBuffer(data, FORMAT_POW_TO_CLIENT, {});
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
SERVER.SendCloseSocket(Socket, "FORMAT_POW_TO_CLIENT")
|
||||
return 0;
|
||||
}
|
||||
if(CompareArr(Buf.addrArr, SERVER.addrArr) === 0)
|
||||
{
|
||||
Node.Self = true
|
||||
AddNodeInfo(Node, "END: SELF")
|
||||
SERVER.SendCloseSocket(Socket, "SELF")
|
||||
return ;
|
||||
}
|
||||
var addrStr = GetHexFromAddres(Buf.addrArr);
|
||||
if(!Node.StartFindList && addrStr !== Node.addrStr)
|
||||
{
|
||||
AddNodeInfo(Node, "END: CHANGED ADDR: " + Node.addrStr.substr(0, 16) + "->" + addrStr.substr(0, 16))
|
||||
SERVER.SendCloseSocket(Socket, "ADDRESS_HAS_BEEN_CHANGED")
|
||||
return ;
|
||||
}
|
||||
if(Node.addrStrTemp)
|
||||
{
|
||||
AddNodeInfo(Node, "Set Addr = " + addrStr)
|
||||
Node.addrStr = addrStr
|
||||
SERVER.CheckNodeMap(Node)
|
||||
}
|
||||
var Result = false;
|
||||
if(Buf.PubKeyType === 2 || Buf.PubKeyType === 3)
|
||||
{
|
||||
Result = secp256k1.verify(Buffer.from(shaarr(addrStr)), Buffer.from(Buf.Sign), Buffer.from([Buf.PubKeyType].concat(Buf.addrArr)))
|
||||
if(!Result)
|
||||
{
|
||||
Result = secp256k1.verify(Buffer.from(sha3(addrStr)), Buffer.from(Buf.Sign), Buffer.from([Buf.PubKeyType].concat(Buf.addrArr)))
|
||||
}
|
||||
}
|
||||
if(!Result)
|
||||
{
|
||||
ToLog("END: ERROR_SIGN_SERVER ADDR: " + addrStr.substr(0, 16) + " from ip: " + Socket.remoteAddress)
|
||||
AddNodeInfo(Node, "END: ERROR_SIGN_SERVER ADDR: " + addrStr.substr(0, 16) + " from ip: " + Socket.remoteAddress)
|
||||
SERVER.SendCloseSocket(Socket, "ERROR_SIGN_SERVER")
|
||||
return ;
|
||||
}
|
||||
if(Buf.MIN_POWER_POW_HANDSHAKE > 1 + MIN_POWER_POW_HANDSHAKE)
|
||||
{
|
||||
ToLog("END: BIG_MIN_POWER_POW_HANDSHAKE ADDR: " + addrStr.substr(0, 16) + " from ip: " + Socket.remoteAddress)
|
||||
return 0;
|
||||
}
|
||||
var TestNode = SERVER.NodesMap[addrStr];
|
||||
if(TestNode && TestNode !== Node)
|
||||
{
|
||||
if(GetSocketStatus(TestNode.Socket))
|
||||
{
|
||||
AddNodeInfo(Node, "DoubleConnection find")
|
||||
Node.DoubleConnection = true
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
AddNodeInfo(Node, "DoubleConnection find")
|
||||
TestNode.DoubleConnection = true
|
||||
}
|
||||
}
|
||||
Node.PubKey = Buffer.from([Buf.PubKeyType].concat(Buf.addrArr))
|
||||
Node.addrArr = Buf.addrArr
|
||||
Node.addrStr = addrStr
|
||||
if(CompareArr(SERVER.addrArr, Node.addrArr) === 0)
|
||||
{
|
||||
Node.Self = 1
|
||||
return 0;
|
||||
}
|
||||
var Hash = shaarr2(Buf.addrArr, Buf.HashRND);
|
||||
var nonce = CreateNoncePOWExternMinPower(Hash, 0, Buf.MIN_POWER_POW_HANDSHAKE);
|
||||
var Info;
|
||||
if(WALLET.WalletOpen && IsDeveloperAccount(WALLET.PubKeyArr))
|
||||
{
|
||||
Info = this.GetPOWClientData(0)
|
||||
Info.Reconnect = 255
|
||||
Info.Sign = secp256k1.sign(SHA3BUF(Hash), WALLET.KeyPair.getPrivateKey('')).signature
|
||||
Result = CheckDevelopSign(Hash, Info.Sign)
|
||||
if(!Result)
|
||||
{
|
||||
throw "ERROR DEVELOPSIGN!";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Info = this.GetPOWClientData(nonce)
|
||||
Info.PubKeyType = SERVER.PubKeyType
|
||||
Info.Sign = secp256k1.sign(Buffer.from(Hash), SERVER.KeyPair.getPrivateKey('')).signature
|
||||
}
|
||||
var BufWrite = BufLib.GetBufferFromObject(Info, FORMAT_POW_TO_SERVER, 1200, {});
|
||||
var BufAll = SERVER.GetBufFromData("POW_CONNECT6", BufWrite, 1);
|
||||
Socket.write(BufAll)
|
||||
return 1;
|
||||
}
|
||||
GetPOWClientData(nonce)
|
||||
{
|
||||
var Node = this;
|
||||
var Info = {};
|
||||
Info.DEF_NETWORK = GetNetworkName()
|
||||
Info.DEF_VERSION = DEF_VERSION
|
||||
Info.DEF_CLIENT = DEF_CLIENT
|
||||
Info.addrArr = SERVER.addrArr
|
||||
Info.ToIP = Node.ip
|
||||
Info.ToPort = Node.port
|
||||
Info.FromIP = SERVER.ip
|
||||
Info.FromPort = SERVER.port
|
||||
Info.nonce = nonce
|
||||
Info.Reconnect = 0
|
||||
Info.SendBytes = 0
|
||||
Info.SecretForReconnect = []
|
||||
Info.Reserv = []
|
||||
if(GrayConnect())
|
||||
Info.GrayConnect = 1
|
||||
return Info;
|
||||
}
|
||||
write(BufWrite)
|
||||
{
|
||||
if(!this.Socket)
|
||||
return ;
|
||||
socketWrite(this.Socket, BufWrite)
|
||||
try
|
||||
{
|
||||
this.Socket.write(BufWrite)
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
ToError(e)
|
||||
this.Socket.WasClose = 1
|
||||
this.Socket.SocketStatus = 0
|
||||
this.Socket.Node = undefined
|
||||
}
|
||||
}
|
||||
};
|
||||
global.socketInit = function (Socket,Str)
|
||||
{
|
||||
if(!Socket)
|
||||
return ;
|
||||
Socket.GetBytes = 0;
|
||||
Socket.SendBytes = 0;
|
||||
Socket.ConnectID = "" + ConnectIDCount + Str;
|
||||
ConnectIDCount++;
|
||||
};
|
||||
global.socketRead = function (Socket,Buf)
|
||||
{
|
||||
Socket.GetBytes += Buf.length;
|
||||
};
|
||||
global.socketWrite = function (Socket,Buf)
|
||||
{
|
||||
Socket.SendBytes += Buf.length;
|
||||
};
|
||||
global.CloseSocket = function (Socket,StrError,bHide)
|
||||
{
|
||||
if(!Socket || Socket.WasClose)
|
||||
{
|
||||
if(Socket)
|
||||
Socket.SocketStatus = 0;
|
||||
return ;
|
||||
}
|
||||
var Node = Socket.Node;
|
||||
if(Socket.Node && Socket.Node.Socket2 === Socket && Socket.Node.Socket && Socket.Node.Socket.SocketStatus === 200)
|
||||
SetSocketStatus(Socket.Node.Socket, 100);
|
||||
var StrNode = NodeInfo(Socket.Node);
|
||||
Socket.WasClose = 1;
|
||||
Socket.SocketStatus = 0;
|
||||
Socket.Node = undefined;
|
||||
Socket.end();
|
||||
if(!bHide)
|
||||
AddNodeInfo(Node, "CLOSE " + StrNode + " *" + Socket.ConnectID + " - " + StrError);
|
||||
};
|
||||
|
||||
function SetSocketStatus(Socket,Status)
|
||||
{
|
||||
if(Socket && Socket.SocketStatus !== Status)
|
||||
{
|
||||
if(Status === 100 && (Socket.SocketStatus !== 3 && Socket.SocketStatus !== 200))
|
||||
{
|
||||
ToLogTrace("===================ERROR=================== " + Status);
|
||||
return ;
|
||||
}
|
||||
if(Status === 100 && Socket.Node)
|
||||
Socket.Node.LastTime = GetCurrentTime() - 0;
|
||||
Socket.SocketStatus = Status;
|
||||
Socket.TimeStatus = Date.now();
|
||||
}
|
||||
};
|
||||
|
||||
function GetSocketStatus(Socket)
|
||||
{
|
||||
if(Socket && Socket.SocketStatus)
|
||||
{
|
||||
if(Socket.SocketStatus !== 100)
|
||||
{
|
||||
var Delta = Date.now() - Socket.TimeStatus;
|
||||
if(Delta > MAX_WAIT_PERIOD_FOR_STATUS)
|
||||
{
|
||||
CloseSocket(Socket, "MAX_WAIT_PERIOD_FOR_STATUS = " + Socket.SocketStatus + " time = " + Delta);
|
||||
}
|
||||
}
|
||||
return Socket.SocketStatus;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
function SocketInfo(Socket)
|
||||
{
|
||||
if(Socket)
|
||||
return "*" + Socket.ConnectID;
|
||||
else
|
||||
return "";
|
||||
};
|
||||
|
||||
function SocketStatistic(Socket)
|
||||
{
|
||||
if(!Socket)
|
||||
return "";
|
||||
var Str = "";
|
||||
if(!Socket.SendBytes)
|
||||
Socket.SendBytes = 0;
|
||||
if(!Socket.GetBytes)
|
||||
Socket.GetBytes = 0;
|
||||
if(Socket.SendBytes)
|
||||
Str += " Send=" + Socket.SendBytes;
|
||||
if(Socket.GetBytes)
|
||||
Str += " Get=" + Socket.GetBytes;
|
||||
if(GetSocketStatus(Socket))
|
||||
Str += " SocketStatus=" + GetSocketStatus(Socket);
|
||||
if(Str === "")
|
||||
Str = "0";
|
||||
return Str;
|
||||
};
|
||||
|
||||
function NodeInfo(Node)
|
||||
{
|
||||
if(Node)
|
||||
return "" + Node.ip + ":" + Node.port + " " + SocketInfo(Node.Socket);
|
||||
else
|
||||
return "";
|
||||
};
|
||||
|
||||
function NodeName(Node)
|
||||
{
|
||||
if(!Node)
|
||||
return "";
|
||||
if(Node.Name)
|
||||
return Node.Name;
|
||||
if(LOCAL_RUN)
|
||||
return "" + Node.port;
|
||||
else
|
||||
{
|
||||
return "" + Node.ip + ":" + Node.addrStr.substr(0, 6);
|
||||
}
|
||||
};
|
||||
|
||||
function FindNodeByAddr(Addr,bConnect)
|
||||
{
|
||||
var Node = SERVER.NodesMap[Addr.trim()];
|
||||
if(Node && Node.ConnectStatus() === 100)
|
||||
return Node;
|
||||
if(Node && bConnect)
|
||||
{
|
||||
Node.NextConnectDelta = 1000;
|
||||
SERVER.StartConnectTry(Node);
|
||||
return false;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
function AddNodeInfo(Node,Str,bSet)
|
||||
{
|
||||
if(!global.STAT_MODE)
|
||||
return ;
|
||||
if(!Node)
|
||||
return ;
|
||||
if(!Node.Info)
|
||||
Node.Info = "";
|
||||
if(bSet)
|
||||
{
|
||||
Node.Info = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Node.Socket && Node.Socket.Info)
|
||||
{
|
||||
Node.Info += Node.Socket.Info + "\n";
|
||||
Node.Socket.Info = "";
|
||||
}
|
||||
}
|
||||
if(Node.Info.length > 1000)
|
||||
{
|
||||
Node.PrevInfo = Node.Info;
|
||||
Node.Info = "";
|
||||
}
|
||||
{
|
||||
var timesend = GetStrOnlyTimeUTC();
|
||||
Str = timesend + " " + Str;
|
||||
Node.Info += Str + "\n";
|
||||
}
|
||||
};
|
||||
global.SocketStatistic = SocketStatistic;
|
||||
global.GetSocketStatus = GetSocketStatus;
|
||||
global.SetSocketStatus = SetSocketStatus;
|
||||
global.NodeInfo = NodeInfo;
|
||||
global.NodeName = NodeName;
|
||||
global.SocketInfo = SocketInfo;
|
||||
global.FindNodeByAddr = FindNodeByAddr;
|
||||
global.AddNodeInfo = AddNodeInfo;
|
||||
503
Source/core/rest-loader.js
Normal file
503
Source/core/rest-loader.js
Normal file
@@ -0,0 +1,503 @@
|
||||
/*
|
||||
* @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";
|
||||
module.exports = class CRest extends require("./db/block-db")
|
||||
{
|
||||
constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual)
|
||||
{
|
||||
super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual)
|
||||
}
|
||||
CheckSyncRest()
|
||||
{
|
||||
var BlockNumTime = GetCurrentBlockNumByTime();
|
||||
var Delta = BlockNumTime - this.BlockNumDB;
|
||||
if(Delta > REST_START_COUNT + DELTA_BLOCK_ACCOUNT_HASH + 500)
|
||||
{
|
||||
var BlockNumRest = GetCurrentRestNum(REST_START_COUNT + DELTA_BLOCK_ACCOUNT_HASH + 500);
|
||||
if(this.BlockNumDB >= this.BlockNumDBMin && this.BlockNumDB <= this.BlockNumDBMin + BLOCK_PROCESSING_LENGTH2)
|
||||
{
|
||||
}
|
||||
else
|
||||
if(BlockNumRest > this.BlockNumDB)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
this.LoadRestContext = undefined
|
||||
return ;
|
||||
}
|
||||
this.LoadRestContext = {Mode:0, BlockNum:BlockNumRest, BlockNumRest:BlockNumRest, WasDelta:Delta, BlockNumProof:BlockNumRest + DELTA_BLOCK_ACCOUNT_HASH,
|
||||
CountProof:COUNT_BLOCKS_FOR_LOAD, StartTimeHistory:Date.now(), MaxTimeOut:600 * 1000, LoopSyncRest:1, SendGetHeaderCount:0,
|
||||
ReceiveHeaderCount:0, ArrProof:[], MapSend:{}}
|
||||
for(var i = 0; i < this.NodesArr.length; i++)
|
||||
{
|
||||
this.NodesArr[i].SendRestGetHeader = 0
|
||||
}
|
||||
ToLog("**********START REST MODE: " + this.LoadRestContext.BlockNumProof)
|
||||
}
|
||||
else
|
||||
{
|
||||
this.LoadRestContext = undefined
|
||||
}
|
||||
}
|
||||
LoopSyncRest()
|
||||
{
|
||||
let Context = this.LoadRestContext;
|
||||
switch(Context.Mode)
|
||||
{
|
||||
case 0:
|
||||
var ArrNodes = this.GetActualNodes();
|
||||
for(var i = 0; i < ArrNodes.length; i++)
|
||||
{
|
||||
var Node = ArrNodes[i];
|
||||
if(!Node || Node.SendRestGetHeader)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Node.SendRestGetHeader = 1
|
||||
ToLog("Send rest get headers from " + Context.BlockNumProof + " to " + NodeName(Node), 2)
|
||||
this.SendF(Node, {"Method":"GETBLOCKHEADER", "Data":{Foward:1, BlockNum:Context.BlockNumProof, Hash:[]}, "Context":{F:this.RETBLOCKHEADER_REST.bind(this)},
|
||||
})
|
||||
Context.SendGetHeaderCount++
|
||||
break;
|
||||
}
|
||||
if(Context.ReceiveHeaderCount >= COUNT_NODE_PROOF)
|
||||
{
|
||||
Context.Mode = 2
|
||||
ToLog("Next mode: " + Context.Mode + " Receive:" + Context.ReceiveHeaderCount + "/" + Context.SendGetHeaderCount, 2)
|
||||
}
|
||||
break;
|
||||
case 1000:
|
||||
break;
|
||||
case 2:
|
||||
var MapSumPower = {};
|
||||
for(var i = 0; i < Context.ArrProof.length; i++)
|
||||
{
|
||||
var Item = Context.ArrProof[i];
|
||||
if(!MapSumPower[Item.SumPower])
|
||||
MapSumPower[Item.SumPower] = 0
|
||||
MapSumPower[Item.SumPower]++
|
||||
}
|
||||
var MaxCount = 0, MaxPow = 0;
|
||||
for(var key in MapSumPower)
|
||||
{
|
||||
if(MapSumPower[key] >= MaxCount)
|
||||
{
|
||||
MaxCount = MapSumPower[key]
|
||||
MaxPow = parseInt(key)
|
||||
}
|
||||
}
|
||||
if(MaxCount < 2 || MaxPow === 0)
|
||||
{
|
||||
ToLog("****************************************************************** Error MaxPow=" + MaxPow + " - reload.")
|
||||
this.CheckSyncRest()
|
||||
return ;
|
||||
}
|
||||
for(var i = 0; i < Context.ArrProof.length; i++)
|
||||
{
|
||||
var Item = Context.ArrProof[i];
|
||||
if(Item.SumPower !== MaxPow)
|
||||
{
|
||||
var Str = "BAD SumPower: " + Item.SumPower + "/" + MaxPow;
|
||||
ToLog(Str + " from: " + NodeName(Item.Node), 2)
|
||||
}
|
||||
else
|
||||
if(Item.SumPower && Item.arr.length >= Context.CountProof)
|
||||
{
|
||||
Item.OK = 1
|
||||
Context.BlockProof = Item.arr[0]
|
||||
}
|
||||
}
|
||||
Context.Mode++
|
||||
ToLog("Next mode: " + Context.Mode + " SumPower:" + MaxPow, 2)
|
||||
break;
|
||||
case 3:
|
||||
if(global.TX_PROCESS && global.TX_PROCESS.RunRPC)
|
||||
{
|
||||
Context.Mode++
|
||||
ToLog("Next mode: " + Context.Mode, 2)
|
||||
var Block = {BlockNum:Context.BlockNumRest};
|
||||
this.BlockNumDB = Block.BlockNum
|
||||
this.BlockNumDBMin = Block.BlockNum
|
||||
this.WriteBlockHeaderDB(Block)
|
||||
this.UseTruncateBlockDB = undefined
|
||||
ToLog("Start run TXPrepareLoadRest", 2)
|
||||
global.TX_PROCESS.RunRPC("TXPrepareLoadRest", Block.BlockNum, function (Err,Params)
|
||||
{
|
||||
Context.Mode++
|
||||
ToLog("Next mode: " + Context.Mode, 2)
|
||||
})
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
break;
|
||||
case 5:
|
||||
let BlockProof = Context.BlockProof;
|
||||
var SendCount = 0;
|
||||
if(BlockProof)
|
||||
for(var i = 0; i < Context.ArrProof.length; i++)
|
||||
{
|
||||
let Item = Context.ArrProof[i];
|
||||
if(Item.OK)
|
||||
{
|
||||
SendCount++
|
||||
ToLog("Send rest get block proof:" + BlockProof.BlockNum + " to " + NodeName(Item.Node), 2)
|
||||
this.SendF(Item.Node, {"Method":"GETBLOCK", "Data":{BlockNum:BlockProof.BlockNum, TreeHash:BlockProof.TreeHash}, "Context":{F:function (Info)
|
||||
{
|
||||
if(Context.TxProof)
|
||||
return ;
|
||||
var Data = BufLib.GetObjectFromBuffer(Info.Data, FORMAT_BLOCK_TRANSFER, WRK_BLOCK_TRANSFER);
|
||||
Info.Data = undefined
|
||||
if(Data.BlockNum !== BlockProof.BlockNum || CompareArr(Data.TreeHash, BlockProof.TreeHash) !== 0)
|
||||
{
|
||||
ToLog("Error get proof block from " + NodeName(Item.Node), 2)
|
||||
return ;
|
||||
}
|
||||
var TreeHash = CalcTreeHashFromArrBody(Data.BlockNum, Data.arrContent);
|
||||
if(CompareArr(BlockProof.TreeHash, TreeHash) !== 0)
|
||||
{
|
||||
ToLog("Error TreeHash in proof block from " + NodeName(Item.Node), 2)
|
||||
return ;
|
||||
}
|
||||
ToLog("GET BLOCK proof from " + NodeName(Item.Node), 2)
|
||||
var FindTx = undefined;
|
||||
for(var n = 0; n < Data.arrContent.length; n++)
|
||||
{
|
||||
var Body = Data.arrContent[n];
|
||||
if(Body[0] === TYPE_TRANSACTION_ACC_HASH)
|
||||
{
|
||||
try
|
||||
{
|
||||
FindTx = BufLib.GetObjectFromBuffer(Body, FORMAT_ACCOUNT_HASH3, {})
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
ToLog("Error parsing Body[" + n + "] block proof: " + e, 2)
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!FindTx)
|
||||
return ;
|
||||
Context.TxProof = FindTx
|
||||
Context.Mode++
|
||||
ToLog("Next mode: " + Context.Mode, 2)
|
||||
Context.AccTaskList = []
|
||||
Context.AccTaskFinished = 0
|
||||
var AccCount = FindTx.AccountMax + 1;
|
||||
for(var n = 0; n < AccCount; n += MAX_ACCOUNTS_TRANSFER)
|
||||
{
|
||||
var Task = {StartNum:n, Count:MAX_ACCOUNTS_TRANSFER, Time:0, MapSend:{}};
|
||||
if(Task.StartNum + Task.Count > AccCount)
|
||||
Task.Count = AccCount - Task.StartNum
|
||||
Context.AccTaskList.push(Task)
|
||||
}
|
||||
Context.SmartTaskList = []
|
||||
Context.SmartTaskFinished = 0
|
||||
for(var n = 0; n < FindTx.SmartCount; n += MAX_SMARTS_TRANSFER)
|
||||
{
|
||||
var Task = {StartNum:n, Count:MAX_SMARTS_TRANSFER, Time:0, MapSend:{}};
|
||||
if(Task.StartNum + Task.Count > FindTx.SmartCount)
|
||||
Task.Count = FindTx.SmartCount - Task.StartNum
|
||||
Context.SmartTaskList.push(Task)
|
||||
}
|
||||
}}, })
|
||||
if(SendCount >= 5)
|
||||
break;
|
||||
}
|
||||
}
|
||||
Context.Mode++
|
||||
ToLog("Next mode: " + Context.Mode, 2)
|
||||
break;
|
||||
case 6:
|
||||
break;
|
||||
case 7:
|
||||
if(Context.AccTaskFinished === Context.AccTaskList.length)
|
||||
{
|
||||
Context.Mode++
|
||||
ToLog("Next mode: " + Context.Mode, 2)
|
||||
break;
|
||||
}
|
||||
var CurTime = Date.now();
|
||||
for(var i = 0; i < Context.AccTaskList.length; i++)
|
||||
{
|
||||
let Task = Context.AccTaskList[i];
|
||||
var Delta = CurTime - Task.Time;
|
||||
if(Delta > 5 * 1000 && !Task.OK)
|
||||
{
|
||||
var Ret = this.GetNextNode(Task, "", 1);
|
||||
if(Ret.Result)
|
||||
{
|
||||
ToLog("Send GETREST Num:" + Task.StartNum + "-" + Task.Count + " to " + NodeName(Ret.Node), 2)
|
||||
var SELF = this;
|
||||
this.SendF(Ret.Node, {"Method":"GETREST", "Data":{BlockNum:Context.BlockNumRest, AccNum:Task.StartNum, Count:Task.Count, AccHash:Context.TxProof.AccHash},
|
||||
"Context":{F:function (Info)
|
||||
{
|
||||
if(Task.OK)
|
||||
return ;
|
||||
var Data = SELF.DataFromF(Info);
|
||||
if(!Data.Result)
|
||||
return ;
|
||||
if(Data.Version !== 1)
|
||||
{
|
||||
ToLog("ERROR Version Result GETREST Num:" + Task.StartNum + " from " + NodeName(Info.Node), 2)
|
||||
return ;
|
||||
}
|
||||
if(CompareArrL(Data.ProofHash, Context.TxProof.AccHash) !== 0)
|
||||
{
|
||||
ToLog("ERROR PROOF HASH Result GETREST Num:" + Task.StartNum + " Hash: " + GetHexFromArr(Data.ProofHash) + "/" + GetHexFromArr(Context.TxProof.AccHash) + " from " + NodeName(Info.Node),
|
||||
2)
|
||||
return ;
|
||||
}
|
||||
var ArrM = [];
|
||||
for(var i = 0; i < Data.Arr.length; i++)
|
||||
{
|
||||
ArrM[i] = shaarr(Data.Arr[i])
|
||||
}
|
||||
var GetHash = CheckMerkleProof(Data.ProofArrL, ArrM, Data.ProofArrR);
|
||||
if(CompareArrL(GetHash, Context.TxProof.AccHash) !== 0)
|
||||
{
|
||||
ToLog("ERROR CALC PROOF HASH Result GETREST Num:" + Task.StartNum + " Hash: " + GetHexFromArr(GetHash) + "/" + GetHexFromArr(Context.TxProof.AccHash) + " from " + NodeName(Info.Node),
|
||||
2)
|
||||
return ;
|
||||
}
|
||||
ToLog("OK Result GETREST Num:" + Task.StartNum + " arr=" + Data.Arr.length + " from " + NodeName(Info.Node), 2)
|
||||
if(!global.TX_PROCESS || !global.TX_PROCESS.RunRPC)
|
||||
{
|
||||
ToLog("ERROR global.TX_PROCESS")
|
||||
return ;
|
||||
}
|
||||
Task.OK = 1
|
||||
global.TX_PROCESS.RunRPC("TXWriteAccArr", {StartNum:Task.StartNum, Arr:Data.Arr}, function (Err,Params)
|
||||
{
|
||||
Context.AccTaskFinished++
|
||||
})
|
||||
}}, })
|
||||
Task.Time = CurTime
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if(Context.SmartTaskFinished === Context.SmartTaskList.length)
|
||||
{
|
||||
Context.Mode++
|
||||
ToLog("Next mode: " + Context.Mode, 2)
|
||||
break;
|
||||
}
|
||||
var CurTime = Date.now();
|
||||
for(var i = 0; i < Context.SmartTaskList.length; i++)
|
||||
{
|
||||
let Task = Context.SmartTaskList[i];
|
||||
var Delta = CurTime - Task.Time;
|
||||
if(Delta > 3 * 1000 && !Task.OK)
|
||||
{
|
||||
var Ret = this.GetNextNode(Task, "", 1);
|
||||
if(Ret.Result)
|
||||
{
|
||||
ToLog("Send GETSMART Num:" + Task.StartNum + "-" + Task.Count + " to " + NodeName(Ret.Node), 2)
|
||||
var SELF = this;
|
||||
this.SendF(Ret.Node, {"Method":"GETSMART", "Data":{BlockNum:Context.BlockNumRest, SmartNum:Task.StartNum, Count:Task.Count},
|
||||
"Context":{F:function (Info)
|
||||
{
|
||||
if(Task.OK)
|
||||
return ;
|
||||
var Data = SELF.DataFromF(Info);
|
||||
if(!Data.Result)
|
||||
return ;
|
||||
ToLog("Result GETSMART Num:" + Task.StartNum + " arr=" + Data.Arr.length + " from " + NodeName(Info.Node), 2)
|
||||
Task.Node = Info.Node
|
||||
if(!global.TX_PROCESS || !global.TX_PROCESS.RunRPC)
|
||||
return ;
|
||||
Task.OK = 1
|
||||
global.TX_PROCESS.RunRPC("TXWriteSmartArr", {StartNum:Task.StartNum, Arr:Data.Arr}, function (Err,Params)
|
||||
{
|
||||
Context.SmartTaskFinished++
|
||||
})
|
||||
}}, })
|
||||
Task.Time = CurTime
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
if(!global.TX_PROCESS || !global.TX_PROCESS.RunRPC)
|
||||
return ;
|
||||
var ErrSmartNum = CheckHashSmarts(Context.TxProof.SmartHash);
|
||||
if(ErrSmartNum > 0)
|
||||
{
|
||||
var Str = "Error hash in smart num: " + ErrSmartNum;
|
||||
ToLog(Str, 2)
|
||||
var t = Math.trunc(ErrSmartNum / MAX_SMARTS_TRANSFER);
|
||||
var Task = Context.SmartTaskList[t];
|
||||
if(!Task)
|
||||
{
|
||||
ToLog("error task number: " + t)
|
||||
Context.Mode = 100
|
||||
}
|
||||
else
|
||||
{
|
||||
Task.OK = 0
|
||||
Context.Mode--
|
||||
Context.SmartTaskFinished--
|
||||
this.AddToBan(Task.Node, Str)
|
||||
}
|
||||
break;
|
||||
}
|
||||
var SELF = this;
|
||||
global.TX_PROCESS.RunRPC("TXWriteAccHash", {}, function (Err,Params)
|
||||
{
|
||||
if(!Params)
|
||||
return ;
|
||||
if(CompareArr(Context.TxProof.AccHash, Params.AccHash) === 0 && CompareArr(Context.TxProof.SmartHash, Params.SmartHash) === 0)
|
||||
{
|
||||
Context.Mode++
|
||||
ToLog("Next mode: " + Context.Mode, 2)
|
||||
}
|
||||
else
|
||||
{
|
||||
ToLog("ERROR RESTS LOAD:")
|
||||
ToLog("Must AccHash:" + GetHexFromArr(Context.TxProof.AccHash))
|
||||
ToLog("Must SmartHash:" + GetHexFromArr(Context.TxProof.SmartHash))
|
||||
ToLog("Write AccHash:" + GetHexFromArr(Params.AccHash))
|
||||
ToLog("Write SmartHash:" + GetHexFromArr(Params.SmartHash))
|
||||
SELF.BlockNumDB = 0
|
||||
SELF.BlockNumDBMin = 0
|
||||
SELF.UseTruncateBlockDB = undefined
|
||||
global.TX_PROCESS.RunRPC("TXPrepareLoadRest", 0, function (Err,Params)
|
||||
{
|
||||
})
|
||||
Context.Mode = 100
|
||||
}
|
||||
})
|
||||
Context.Mode++
|
||||
ToLog("Next mode: " + Context.Mode, 2)
|
||||
break;
|
||||
case 10:
|
||||
break;
|
||||
case 11:
|
||||
var Context2 = this.LoadHistoryContext;
|
||||
Context2.BlockNum = this.LoadRestContext.BlockNumRest
|
||||
Context2.StartTimeHistory = Date.now()
|
||||
Context.Mode = 200
|
||||
break;
|
||||
case 200:
|
||||
ToLog("Error state!")
|
||||
break;
|
||||
}
|
||||
}
|
||||
RETBLOCKHEADER_REST(Info, CurTime)
|
||||
{
|
||||
if(Info.Node.SendRestGetHeader === 2)
|
||||
return ;
|
||||
Info.Node.SendRestGetHeader = 2
|
||||
var Context = this.LoadRestContext;
|
||||
var BufRead = BufLib.GetReadBuffer(Info.Data);
|
||||
var arr = this.GetBlockArrFromBuffer_Load(BufRead, Info);
|
||||
ToLog("RETBLOCKHEADER_FOWARD SyncRest from " + NodeName(Info.Node) + " arr=" + arr.length, 2)
|
||||
Context.ReceiveHeaderCount++
|
||||
var MinSumPow = 10 * Context.CountProof;
|
||||
var SumPower = 0;
|
||||
if(arr.length >= Context.CountProof)
|
||||
for(var i = 0; i < Context.CountProof; i++)
|
||||
{
|
||||
SumPower += arr[i].Power
|
||||
}
|
||||
if(SumPower <= MinSumPow)
|
||||
SumPower = 0
|
||||
Context.ArrProof.push({Node:Info.Node, SumPower:SumPower, arr:arr, BufRead:BufRead})
|
||||
}
|
||||
static
|
||||
GETSMART_F()
|
||||
{
|
||||
return "{\
|
||||
SmartNum:uint,\
|
||||
Count:uint,\
|
||||
}";
|
||||
}
|
||||
static
|
||||
RETSMART_F()
|
||||
{
|
||||
return global.FORMAT_SMART_TRANSFER;
|
||||
}
|
||||
static
|
||||
GETREST_F()
|
||||
{
|
||||
return "{\
|
||||
BlockNum:uint,\
|
||||
AccNum:uint,\
|
||||
Count:uint,\
|
||||
AccHash:hash,\
|
||||
}";
|
||||
}
|
||||
static
|
||||
RETREST_F()
|
||||
{
|
||||
return global.FORMAT_REST_TRANSFER;
|
||||
}
|
||||
SendLoadToBegin()
|
||||
{
|
||||
return ;
|
||||
if(!this.BlockNumDBMin)
|
||||
return ;
|
||||
if(!this.ContextSendLoadToBegin)
|
||||
this.ContextSendLoadToBegin = {Time:0, MapSend:{}}
|
||||
var Context = this.ContextSendLoadToBegin;
|
||||
var CurTime = Date.now();
|
||||
var Delta = CurTime - Context.Time;
|
||||
if(Delta < 2 * 1000)
|
||||
return ;
|
||||
var BlockDB = this.ReadBlockHeaderDB(this.BlockNumDBMin + 1);
|
||||
if(!BlockDB)
|
||||
return ;
|
||||
Context.BlockNum = BlockDB.BlockNum
|
||||
var Ret = this.GetNextNode(Context, Context.BlockNum, 1);
|
||||
if(Ret.Result)
|
||||
{
|
||||
var Node = Ret.Node;
|
||||
ToLog("LOAD_TO_BEGIN - from: " + BlockDB.BlockNum + " to " + NodeName(Node), 2)
|
||||
Context.Time = CurTime
|
||||
this.SendF(Node, {"Method":"GETBLOCKHEADER", "Data":{Foward:0, BlockNum:Context.BlockNum, Hash:BlockDB.Hash, IsSum:0, Count:global.COUNT_HISTORY_BLOCKS_FOR_LOAD},
|
||||
"Context":{F:function (Info)
|
||||
{
|
||||
ToLog("GET LOAD_TO_BEGIN from " + NodeName(Info.Node) + " Length=" + Info.Data.length, 2)
|
||||
}}})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function CheckHashSmarts(LastSumHash)
|
||||
{
|
||||
DApps.Smart.Close();
|
||||
var MaxNum = DApps.Smart.GetMaxNum();
|
||||
var Item = DApps.Smart.DBSmart.Read(MaxNum);
|
||||
if(CompareArr(Item.SumHash, LastSumHash) !== 0)
|
||||
return MaxNum;
|
||||
var WorkStruct = {};
|
||||
for(var Num = MaxNum; Num >= 1; Num--)
|
||||
{
|
||||
var PrevItem = DApps.Smart.DBSmart.Read(Num - 1);
|
||||
if(!PrevItem)
|
||||
return Num;
|
||||
var WasSumHash = Item.SumHash;
|
||||
Item.SumHash = [];
|
||||
var Buf = BufLib.GetBufferFromObject(Item, DApps.Smart.FORMAT_ROW, 20000, WorkStruct);
|
||||
var Hash = sha3(Buf);
|
||||
var SumHash = sha3arr2(PrevItem.SumHash, Hash);
|
||||
if(CompareArr(SumHash, WasSumHash) !== 0)
|
||||
return Num;
|
||||
Item = PrevItem;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
73
Source/core/rest_tables.js
Normal file
73
Source/core/rest_tables.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* @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
|
||||
*/
|
||||
|
||||
|
||||
function DoRest(r,t,e)
|
||||
{
|
||||
var u = r.Arr[0], o = Math.floor(e / REST_BLOCK_SCALE);
|
||||
if(o !== Math.floor((u.BlockNum - 1) / REST_BLOCK_SCALE))
|
||||
{
|
||||
for(var n = GetRestArr(o), l = [], a = n.length - 2; 0 <= a; a--)
|
||||
l.push(n[a] * REST_BLOCK_SCALE);
|
||||
RestPush(r, l, e, 1);
|
||||
}
|
||||
r.Arr[0] = {BlockNum:e, Value:t.Value};
|
||||
};
|
||||
|
||||
function RestPush(r,t,e,u)
|
||||
{
|
||||
var o = r.Arr[u - 1], n = r.Arr[u];
|
||||
if(1 < u)
|
||||
{
|
||||
var l = t[u - 2];
|
||||
if(o.BlockNum > l)
|
||||
return ;
|
||||
}
|
||||
if(n.BlockNum && n.BlockNum >= e || o.BlockNum >= e)
|
||||
return n.BlockNum = 0, void (n.Value = {});
|
||||
n.BlockNum && u < r.Arr.length - 1 && RestPush(r, t, e, u + 1), r.Arr[u] = o;
|
||||
};
|
||||
|
||||
function GetRestArr(r)
|
||||
{
|
||||
for(var t = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], e = t.length, u = 0; u <= r; u++)
|
||||
for(var o = 0, n = u, l = e - 1; 0 <= l; l--)
|
||||
{
|
||||
var a = t[l];
|
||||
if(t[l] = n, n = a, 0 == ((o = o << 4 | 15) & u))
|
||||
break;
|
||||
if(0 != (o & n))
|
||||
break;
|
||||
}
|
||||
return t;
|
||||
};
|
||||
var RestArrMap = {};
|
||||
|
||||
function GetCurrentRestArr()
|
||||
{
|
||||
var r = GetCurrentBlockNumByTime(), t = Math.floor(r / REST_BLOCK_SCALE), e = RestArrMap[t];
|
||||
if(void 0 === e)
|
||||
{
|
||||
RestArrMap = {}, (e = GetRestArr(t)).length = e.length - 1;
|
||||
for(var u = 0; u < e.length; u++)
|
||||
e[u] = e[u] * REST_BLOCK_SCALE;
|
||||
RestArrMap[t] = e;
|
||||
}
|
||||
return e;
|
||||
};
|
||||
|
||||
function GetCurrentRestNum(r)
|
||||
{
|
||||
for(var t = GetCurrentBlockNumByTime() - r, e = GetCurrentRestArr(), u = e.length - 1; 0 <= u; u--)
|
||||
if(e[u] <= t)
|
||||
return e[u];
|
||||
return 0;
|
||||
};
|
||||
global.DoRest = DoRest, global.GetRestArr = GetRestArr, global.GetCurrentRestArr = GetCurrentRestArr, global.GetCurrentRestNum = GetCurrentRestNum;
|
||||
1239
Source/core/server.js
Normal file
1239
Source/core/server.js
Normal file
File diff suppressed because it is too large
Load Diff
50
Source/core/startlib.js
Normal file
50
Source/core/startlib.js
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* @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
|
||||
*/
|
||||
|
||||
var fs = require("fs");
|
||||
|
||||
function CopyFiles(l,o,t)
|
||||
{
|
||||
if(fs.existsSync(l))
|
||||
for(var e = fs.readdirSync(l), n = 0; n < e.length; n++)
|
||||
{
|
||||
var a = l + "/" + e[n], s = o + "/" + e[n];
|
||||
if(fs.statSync(a).isDirectory())
|
||||
t && (fs.existsSync(s) || fs.mkdirSync(s), CopyFiles(a, s, t));
|
||||
else
|
||||
{
|
||||
var r = fs.readFileSync(a), i = fs.openSync(s, "w");
|
||||
fs.writeSync(i, r, 0, r.length), fs.closeSync(i);
|
||||
}
|
||||
}
|
||||
};
|
||||
global.GetDataPath = function (l)
|
||||
{
|
||||
return "/" !== global.DATA_PATH.substr(global.DATA_PATH.length - 1, 1) && (global.DATA_PATH = global.DATA_PATH + "/"), GetNormalPathString(global.DATA_PATH + l);
|
||||
}, global.GetCodePath = function (l)
|
||||
{
|
||||
return "/" !== global.CODE_PATH.substr(global.CODE_PATH.length - 1, 1) && (global.CODE_PATH = global.CODE_PATH + "/"), GetNormalPathString(global.CODE_PATH + l);
|
||||
}, global.GetNormalPathString = function (l)
|
||||
{
|
||||
return l.split("\\").join("/");
|
||||
}, global.CheckCreateDir = function (l,o,t)
|
||||
{
|
||||
if(l = GetNormalPathString(l), !fs.existsSync(l))
|
||||
{
|
||||
o || console.log("Create: " + l);
|
||||
var e = l.split("/"), n = e[0];
|
||||
t && e.length--;
|
||||
for(var a = 1; a < e.length; a++)
|
||||
n += "/" + e[a], fs.existsSync(n) || fs.mkdirSync(n);
|
||||
}
|
||||
}, global.CopyFiles = CopyFiles, global.ToLog || (global.ToLog = function (l)
|
||||
{
|
||||
console.log(l);
|
||||
});
|
||||
227
Source/core/terahashmining.js
Normal file
227
Source/core/terahashmining.js
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* @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
|
||||
*/
|
||||
|
||||
var START_NONCE = 0;
|
||||
const COUNT_FIND_HASH1 = 64;
|
||||
const DELTA_LONG_MINING = 5000;
|
||||
var BLOCKNUM_ALGO2 = 6560000;
|
||||
if(global.LOCAL_RUN || global.TEST_NETWORK)
|
||||
{
|
||||
BLOCKNUM_ALGO2 = 0;
|
||||
}
|
||||
require('./library.js');
|
||||
require('./crypto-library.js');
|
||||
require('../HTML/JS/terahashlib.js');
|
||||
var DELTA_NONCE = Math.pow(2, 40) * global.MINING_VERSION_NUM;
|
||||
global.CreateHashMinimal = CreateHashMinimal;
|
||||
global.CreatePOWVersionX = CreatePOWVersion3;
|
||||
|
||||
function CreateHashMinimal(Block,MinerID)
|
||||
{
|
||||
if(Block.BlockNum < BLOCKNUM_ALGO2)
|
||||
{
|
||||
throw "BlockNum < BLOCKNUM_ALGO2";
|
||||
return false;
|
||||
}
|
||||
var PrevHashNum = ReadUint32FromArr(Block.PrevHash, 28);
|
||||
var Ret = GetHash(Block.SeqHash, PrevHashNum, Block.BlockNum, MinerID, 0, 0, 0, 0, 0);
|
||||
Block.Hash = Ret.Hash;
|
||||
Block.PowHash = Ret.PowHash;
|
||||
Block.Power = GetPowPower(Block.PowHash);
|
||||
Block.AddrHash = [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];
|
||||
WriteUintToArrOnPos(Block.AddrHash, MinerID, 0);
|
||||
WriteUint32ToArrOnPos(Block.AddrHash, PrevHashNum, 28);
|
||||
return true;
|
||||
};
|
||||
var MAX_MEMORY3 = 0, SHIFT_MASKA3;
|
||||
var BufferNonce3, BufferBlockNum3;
|
||||
var bWasInitVer3, bWasInitVerOK3;
|
||||
|
||||
function InitVer3(Block)
|
||||
{
|
||||
bWasInitVer3 = 1;
|
||||
if(Block.ProcessMemorySize > 0)
|
||||
{
|
||||
var MAXARRAYSIZE = (1 << 30) * 2 - 1;
|
||||
var MaxArrCount = Math.min(Math.trunc(Block.ProcessMemorySize / 8), MAXARRAYSIZE);
|
||||
var BitCount = 0;
|
||||
MAX_MEMORY3 = 1;
|
||||
for(var b = 0; b < 32; b++)
|
||||
{
|
||||
if(MAX_MEMORY3 > MaxArrCount)
|
||||
{
|
||||
BitCount--;
|
||||
MAX_MEMORY3 = MAX_MEMORY3 / 2;
|
||||
break;
|
||||
}
|
||||
BitCount++;
|
||||
MAX_MEMORY3 = MAX_MEMORY3 * 2;
|
||||
}
|
||||
SHIFT_MASKA3 = 32 - BitCount;
|
||||
try
|
||||
{
|
||||
BufferNonce3 = new Uint32Array(MAX_MEMORY3);
|
||||
BufferBlockNum3 = new Uint32Array(MAX_MEMORY3);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
SHIFT_MASKA3 = SHIFT_MASKA3 + 1;
|
||||
MAX_MEMORY3 = MAX_MEMORY3 / 2;
|
||||
ToLog("WAS ALLOC MEMORY ERROR. NEW TRY: " + MAX_MEMORY3);
|
||||
BufferNonce3 = new Uint32Array(MAX_MEMORY3);
|
||||
BufferBlockNum3 = new Uint32Array(MAX_MEMORY3);
|
||||
}
|
||||
bWasInitVerOK3 = 1;
|
||||
ToLog("MAX HASH ITEMS=" + Math.trunc(MAX_MEMORY3 / 1024 / 1024) + " M");
|
||||
}
|
||||
};
|
||||
|
||||
function CreatePOWVersion3(Block,bHashPump)
|
||||
{
|
||||
if(!bWasInitVer3)
|
||||
InitVer3(Block);
|
||||
if(!bWasInitVerOK3)
|
||||
return 0;
|
||||
if(!Block.LastNonce)
|
||||
Block.LastNonce = 0;
|
||||
if(!Block.HashCount)
|
||||
Block.HashCount = 0;
|
||||
if(!Block.LastNonce0)
|
||||
Block.LastNonce0 = 0;
|
||||
if(!Block.MaxLider)
|
||||
{
|
||||
Block.HashCount = 0;
|
||||
Block.MaxLider = {Nonce0:0, Nonce1:0, Nonce2:0, DeltaNum1:0, DeltaNum2:0, Hash1:[255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255], Hash2:[255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255], };
|
||||
}
|
||||
var MaxLider = Block.MaxLider;
|
||||
var RunCount = Block.RunCount;
|
||||
var BlockNum = Block.BlockNum;
|
||||
var Miner = Block.MinerID;
|
||||
var StartNonceRnd = DELTA_NONCE + Block.LastNonce + Math.trunc(3000000000 * Math.random());
|
||||
var List = GetNonceHashArr(BlockNum, Miner, StartNonceRnd, RunCount);
|
||||
for(var n = 0; n < RunCount; n++)
|
||||
{
|
||||
var Nonce = List.ArrNonce[n];
|
||||
var HashNum = List.ArrHash[n] >>> SHIFT_MASKA3;
|
||||
BufferNonce3[HashNum] = Nonce;
|
||||
BufferBlockNum3[HashNum] = BlockNum;
|
||||
}
|
||||
Block.LastNonce += RunCount;
|
||||
if(bHashPump)
|
||||
return ;
|
||||
var Ret = 0;
|
||||
var PrevHashNum = ReadUint32FromArr(Block.PrevHash, 28);
|
||||
var HashBase = GetHashFromNum2(BlockNum, PrevHashNum);
|
||||
var Value1 = FindHashBuffer3(HashBase, BlockNum, Miner, 1);
|
||||
if(Value1)
|
||||
{
|
||||
var Hash1 = XORArr(HashBase, Value1.Hash);
|
||||
if(CompareArr(MaxLider.Hash1, Hash1) > 0)
|
||||
{
|
||||
MaxLider.Hash1 = Hash1;
|
||||
MaxLider.Nonce1 = Value1.Nonce;
|
||||
MaxLider.DeltaNum1 = Value1.DeltaNum;
|
||||
Ret = 1;
|
||||
}
|
||||
}
|
||||
START_NONCE = Block.LastNonce0;
|
||||
var CountEnd = START_NONCE + 50000;
|
||||
var Nonce0;
|
||||
for(Nonce0 = START_NONCE; Nonce0 < CountEnd; Nonce0++)
|
||||
{
|
||||
var HashCurrent = GetHashFromArrNum2(Block.SeqHash, Miner, Nonce0);
|
||||
var Value2 = FindHashBuffer3(HashCurrent, BlockNum, Miner, 1);
|
||||
if(Value2)
|
||||
{
|
||||
var Hash2 = XORArr(HashCurrent, Value2.Hash);
|
||||
if(CompareArr(MaxLider.Hash2, Hash2) > 0)
|
||||
{
|
||||
MaxLider.Nonce0 = Nonce0;
|
||||
MaxLider.Hash2 = Hash2;
|
||||
MaxLider.Nonce2 = Value2.Nonce;
|
||||
MaxLider.DeltaNum2 = Value2.DeltaNum;
|
||||
Ret = 1;
|
||||
if(CompareArr(MaxLider.Hash1, Hash2) > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Block.LastNonce0 = Nonce0;
|
||||
if(Ret)
|
||||
{
|
||||
Block.AddrHash = [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];
|
||||
WriteUintToArrOnPos(Block.AddrHash, Miner, 0);
|
||||
WriteUintToArrOnPos(Block.AddrHash, MaxLider.Nonce0, 6);
|
||||
WriteUintToArrOnPos(Block.AddrHash, MaxLider.Nonce1, 12);
|
||||
WriteUintToArrOnPos(Block.AddrHash, MaxLider.Nonce2, 18);
|
||||
WriteUint16ToArrOnPos(Block.AddrHash, MaxLider.DeltaNum1, 24);
|
||||
WriteUint16ToArrOnPos(Block.AddrHash, MaxLider.DeltaNum2, 26);
|
||||
WriteUint32ToArrOnPos(Block.AddrHash, PrevHashNum, 28);
|
||||
Block.Hash = MaxLider.Hash2;
|
||||
if(CompareArr(MaxLider.Hash1, MaxLider.Hash2) > 0)
|
||||
{
|
||||
Block.PowHash = MaxLider.Hash1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Block.PowHash = MaxLider.Hash2;
|
||||
}
|
||||
if(BlockNum >= global.BLOCKNUM_TICKET_ALGO)
|
||||
Block.Hash = sha3arr2(MaxLider.Hash1, MaxLider.Hash2);
|
||||
else
|
||||
Block.Hash = shaarr2(MaxLider.Hash1, MaxLider.Hash2);
|
||||
var Power = GetPowPower(Block.PowHash);
|
||||
Block.HashCount = (1 << Power) >>> 0;
|
||||
}
|
||||
return Ret;
|
||||
};
|
||||
|
||||
function FindHashBuffer3(HashFind,BlockNum,Miner,CountFind)
|
||||
{
|
||||
var HashNum = ReadIndexFromArr(HashFind);
|
||||
for(var i = 0; i < CountFind; i++)
|
||||
{
|
||||
var Index = HashNum ^ i;
|
||||
var BlockNum2 = BufferBlockNum3[Index];
|
||||
if(BlockNum2 && BlockNum2 > BlockNum - DELTA_LONG_MINING)
|
||||
{
|
||||
var Nonce2 = DELTA_NONCE + BufferNonce3[Index];
|
||||
var Hash2 = GetHashFromNum3(BlockNum2, Miner, Nonce2);
|
||||
return {Hash:Hash2, DeltaNum:BlockNum - BlockNum2, Nonce:Nonce2};
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
function ReadIndexFromArr(arr)
|
||||
{
|
||||
var value = (arr[0] << 23) * 2 + (arr[1] << 16) + (arr[2] << 8) + arr[3];
|
||||
value = value >>> SHIFT_MASKA3;
|
||||
return value;
|
||||
};
|
||||
global.GetNonceHashArr = function (BlockNum,Miner,StartNonceRnd,CountNonce)
|
||||
{
|
||||
var ArrNonce = [];
|
||||
var ArrHash = [];
|
||||
for(var n = 0; n < CountNonce; n++)
|
||||
{
|
||||
var Nonce = StartNonceRnd + n;
|
||||
var HashNonce = GetHashFromNum3(BlockNum, Miner, Nonce);
|
||||
var HashNum = (HashNonce[0] << 23) * 2 + (HashNonce[1] << 16) + (HashNonce[2] << 8) + HashNonce[3];
|
||||
ArrNonce[n] = Nonce;
|
||||
ArrHash[n] = HashNum;
|
||||
}
|
||||
return {ArrNonce:ArrNonce, ArrHash:ArrHash};
|
||||
};
|
||||
368
Source/core/transaction-validator.js
Normal file
368
Source/core/transaction-validator.js
Normal file
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* @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";
|
||||
require("../system/dapp");
|
||||
require("../system/accounts");
|
||||
require("../system/smart");
|
||||
require("../system/file");
|
||||
require("../system/messager");
|
||||
require("../system/names");
|
||||
if(global.PROCESS_NAME === "MAIN" || global.PROCESS_NAME === "TX")
|
||||
require("./wallet");
|
||||
module.exports = class CSmartContract extends require("./block-exchange")
|
||||
{
|
||||
constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual)
|
||||
{
|
||||
super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual)
|
||||
this.BufHashTree = new RBTree(CompareArr)
|
||||
this.BufHashTree.LastAddNum = 0
|
||||
this.SenderMap = {}
|
||||
this.SenderBlockHashMap = {}
|
||||
if(!global.ADDRLIST_MODE && !this.VirtualMode && global.START_SERVER)
|
||||
{
|
||||
setInterval(this.ClearOldSenderMapItem.bind(this), 10000)
|
||||
}
|
||||
}
|
||||
AddBlockToHashTree(Block)
|
||||
{
|
||||
this.BufHashTree.LastAddNum = Block.BlockNum
|
||||
var arr = Block.arrContent;
|
||||
if(arr)
|
||||
{
|
||||
for(var i = 0; i < arr.length; i++)
|
||||
{
|
||||
var HASH = sha3(arr[i]);
|
||||
this.BufHashTree.insert(HASH)
|
||||
}
|
||||
}
|
||||
}
|
||||
DeleteBlockFromHashTree(Block)
|
||||
{
|
||||
var arr = Block.arrContent;
|
||||
if(arr)
|
||||
{
|
||||
for(var i = 0; i < arr.length; i++)
|
||||
{
|
||||
var HASH = sha3(arr[i]);
|
||||
this.BufHashTree.remove(HASH)
|
||||
}
|
||||
}
|
||||
}
|
||||
OnWriteBlock(Block)
|
||||
{
|
||||
this.AddToSenderMap(Block)
|
||||
}
|
||||
OnDelete(Block)
|
||||
{
|
||||
}
|
||||
BlockProcessTX(Block)
|
||||
{
|
||||
if(Block.BlockNum < 1)
|
||||
return ;
|
||||
var COUNT_MEM_BLOCKS = 0;
|
||||
var NUM1 = 1240000;
|
||||
var NUM2 = 1400000;
|
||||
if(global.LOCAL_RUN)
|
||||
{
|
||||
NUM1 = 15
|
||||
NUM2 = 100
|
||||
}
|
||||
if(Block.BlockNum > global.BLOCKNUM_TICKET_ALGO)
|
||||
{
|
||||
NUM1 = 1000000000000
|
||||
NUM2 = 1000000000000
|
||||
}
|
||||
if(Block.BlockNum > NUM1)
|
||||
{
|
||||
COUNT_MEM_BLOCKS = 1
|
||||
if(Block.BlockNum > NUM2)
|
||||
COUNT_MEM_BLOCKS = 60
|
||||
if(this.BufHashTree.LastAddNum !== Block.BlockNum - 1)
|
||||
{
|
||||
this.BufHashTree.clear()
|
||||
for(var num = COUNT_MEM_BLOCKS; num >= 1; num--)
|
||||
{
|
||||
var Block2 = this.ReadBlockDB(Block.BlockNum - num);
|
||||
if(Block2)
|
||||
{
|
||||
this.AddBlockToHashTree(Block2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(var key in DApps)
|
||||
{
|
||||
DApps[key].OnWriteBlockStart(Block)
|
||||
}
|
||||
var arrContentResult = [];
|
||||
var BlockNum = Block.BlockNum;
|
||||
var arr = Block.arrContent;
|
||||
if(arr)
|
||||
for(var i = 0; i < arr.length; i++)
|
||||
{
|
||||
var HASH = sha3(arr[i]);
|
||||
if(this.BufHashTree.find(HASH))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var type = arr[i][0];
|
||||
var App = DAppByType[type];
|
||||
if(App)
|
||||
{
|
||||
App.ResultTx = 0
|
||||
DApps.Accounts.BeginTransaction()
|
||||
var StrHex = GetHexFromArr(HASH);
|
||||
var item;
|
||||
global.CurTrItem = undefined
|
||||
if(global.TreeFindTX)
|
||||
{
|
||||
item = global.TreeFindTX.LoadValue(StrHex)
|
||||
if(item)
|
||||
global.CurTrItem = item.TX
|
||||
}
|
||||
var Result = App.OnWriteTransaction(Block, arr[i], BlockNum, i);
|
||||
var SetResult = Result;
|
||||
if(Result === true)
|
||||
{
|
||||
if(App.ResultTx)
|
||||
SetResult = App.ResultTx
|
||||
if(!DApps.Accounts.CommitTransaction(BlockNum, i))
|
||||
SetResult = 0
|
||||
}
|
||||
else
|
||||
{
|
||||
DApps.Accounts.RollBackTransaction()
|
||||
SetResult = 0
|
||||
}
|
||||
if(SetResult === true)
|
||||
SetResult = 1
|
||||
arrContentResult[i] = SetResult
|
||||
if(item)
|
||||
{
|
||||
var ResultStr = Result;
|
||||
if(Result === true || typeof Result === "number")
|
||||
{
|
||||
ResultStr = "Add to blockchain"
|
||||
if(type === global.TYPE_TRANSACTION_FILE)
|
||||
ResultStr += ": file/" + BlockNum + "/" + i
|
||||
}
|
||||
item.cmd = "RetFindTX"
|
||||
item.ResultStr = "" + ResultStr
|
||||
item.bFinal = 1
|
||||
item.Result = SetResult
|
||||
process.send(item)
|
||||
}
|
||||
global.CurTrItem = undefined
|
||||
}
|
||||
}
|
||||
if(COUNT_MEM_BLOCKS)
|
||||
{
|
||||
var Block2 = this.ReadBlockDB(Block.BlockNum - COUNT_MEM_BLOCKS);
|
||||
if(Block2)
|
||||
this.DeleteBlockFromHashTree(Block2)
|
||||
this.AddBlockToHashTree(Block)
|
||||
}
|
||||
if(arrContentResult.length)
|
||||
process.send({cmd:"WriteBodyResult", BlockNum:Block.BlockNum, arrContentResult:arrContentResult})
|
||||
for(var key in DApps)
|
||||
{
|
||||
DApps[key].OnWriteBlockFinish(Block)
|
||||
}
|
||||
}
|
||||
BlockDeleteTX(Block)
|
||||
{
|
||||
this.BufHashTree.LastAddNum = 0
|
||||
for(var key in DApps)
|
||||
{
|
||||
DApps[key].OnDeleteBlock(Block)
|
||||
}
|
||||
}
|
||||
IsValidTicket(Tr, BlockNum)
|
||||
{
|
||||
this.CheckCreateTicketObject(Tr, BlockNum)
|
||||
if(Tr.power < MIN_POWER_POW_TR)
|
||||
return - 2;
|
||||
if(Tr.num !== BlockNum)
|
||||
return - 3;
|
||||
return 1;
|
||||
}
|
||||
IsValidTransaction(Tr, BlockNum)
|
||||
{
|
||||
if(!Tr.body || Tr.body.length < MIN_TRANSACTION_SIZE || Tr.body.length > MAX_TRANSACTION_SIZE)
|
||||
return - 1;
|
||||
this.CheckCreateTransactionObject(Tr)
|
||||
if(Tr.power - Math.log2(Tr.body.length / 128) < MIN_POWER_POW_TR)
|
||||
return - 2;
|
||||
if(Tr.num !== BlockNum)
|
||||
return - 3;
|
||||
if(Tr.body[0] === TYPE_TRANSACTION_ACC_HASH)
|
||||
return - 4;
|
||||
return 1;
|
||||
}
|
||||
ReWriteDAppTransactions(Length)
|
||||
{
|
||||
if(!TX_PROCESS.Worker)
|
||||
return 0;
|
||||
if(!Length)
|
||||
return 0;
|
||||
var StartNum = this.BlockNumDB - Length + 1;
|
||||
if(StartNum < 0)
|
||||
StartNum = 0
|
||||
var EndNum = this.BlockNumDB;
|
||||
var MinBlock = DApps.Accounts.GetMinBlockAct();
|
||||
if(MinBlock > StartNum)
|
||||
{
|
||||
ToLog("Cant rewrite transactions. Very long length of the rewriting chain. Max length=" + (this.BlockNumDB - MinBlock))
|
||||
return 0;
|
||||
}
|
||||
if(global.TX_PROCESS && global.TX_PROCESS.RunRPC)
|
||||
global.TX_PROCESS.RunRPC("ReWriteDAppTransactions", {StartNum:StartNum, EndNum:EndNum})
|
||||
return 1;
|
||||
}
|
||||
AddDAppTransactions(BlockNum, Arr)
|
||||
{
|
||||
if(BlockNum % PERIOD_ACCOUNT_HASH !== 0)
|
||||
return ;
|
||||
var BlockNumHash = BlockNum - DELTA_BLOCK_ACCOUNT_HASH;
|
||||
if(BlockNumHash < 0)
|
||||
return ;
|
||||
var Item = DApps.Accounts.GetAccountHashItem(BlockNumHash);
|
||||
if(Item)
|
||||
{
|
||||
var Body = [TYPE_TRANSACTION_ACC_HASH];
|
||||
WriteUintToArr(Body, BlockNumHash)
|
||||
WriteArrToArr(Body, Item.AccHash, 32)
|
||||
if(BlockNumHash >= START_BLOCK_ACCOUNT_HASH3)
|
||||
{
|
||||
WriteUintToArr(Body, Item.AccountMax)
|
||||
WriteArrToArr(Body, Item.SmartHash, 32)
|
||||
WriteUintToArr(Body, Item.SmartCount)
|
||||
WriteUintToArr(Body, BlockNum)
|
||||
WriteUintToArr(Body, 0)
|
||||
}
|
||||
var Tr = {body:Body};
|
||||
this.CheckCreateTransactionObject(Tr)
|
||||
Arr.unshift(Tr)
|
||||
}
|
||||
}
|
||||
AddTransactionOwn(Tr)
|
||||
{
|
||||
if(!global.TX_PROCESS.Worker)
|
||||
return - 6;
|
||||
var StrHex = GetHexFromArr(sha3(Tr.body));
|
||||
global.TX_PROCESS.Worker.send({cmd:"FindTX", TX:StrHex})
|
||||
return this.AddTransaction(Tr, 1);
|
||||
}
|
||||
AddToSenderMap(Block)
|
||||
{
|
||||
if(!global.START_SERVER)
|
||||
return ;
|
||||
var BlockNum = Block.BlockNum;
|
||||
var StrBlockHash = GetHexFromArr(Block.Hash);
|
||||
this.SenderBlockHashMap[BlockNum] = StrBlockHash
|
||||
var arr = Block.arrContent;
|
||||
if(arr)
|
||||
{
|
||||
for(var i = 0; i < arr.length; i++)
|
||||
{
|
||||
var type = arr[i][0];
|
||||
var App = DAppByType[type];
|
||||
if(App)
|
||||
{
|
||||
var Body = arr[i];
|
||||
var SenderNum = App.GetSenderNum(BlockNum, Body);
|
||||
if(SenderNum < 0)
|
||||
continue;
|
||||
var ItemArr = this.SenderMap[SenderNum];
|
||||
if(!ItemArr)
|
||||
{
|
||||
ItemArr = []
|
||||
this.SenderMap[SenderNum] = ItemArr
|
||||
}
|
||||
ItemArr.push({BlockNum:BlockNum, StrHash:StrBlockHash})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GetSenderPrioritet(BlockNum, SenderNum)
|
||||
{
|
||||
if(!global.START_SERVER)
|
||||
return 0;
|
||||
if(!this.WasReloadSenderMapFromDB)
|
||||
this.ReloadSenderMapFromDB()
|
||||
if(SenderNum < 0)
|
||||
return MAX_LENGTH_SENDER_MAP;
|
||||
var MaxBlockNum = BlockNum - DELTA_START_SENDER_MAP;
|
||||
if(MaxBlockNum > this.BlockNumDB)
|
||||
return MAX_LENGTH_SENDER_MAP;
|
||||
var ItemArr = this.SenderMap[SenderNum];
|
||||
if(!ItemArr)
|
||||
{
|
||||
return MAX_LENGTH_SENDER_MAP;
|
||||
}
|
||||
for(var i = ItemArr.length - 1; i--; i >= 0)
|
||||
{
|
||||
var Item = ItemArr[i];
|
||||
if(Item.BlockNum <= MaxBlockNum && this.SenderBlockHashMap[Item.BlockNum] === Item.StrHash)
|
||||
{
|
||||
var Delta = MaxBlockNum - Item.BlockNum;
|
||||
if(Delta > MAX_LENGTH_SENDER_MAP)
|
||||
Delta = MAX_LENGTH_SENDER_MAP
|
||||
return Delta;
|
||||
}
|
||||
}
|
||||
return MAX_LENGTH_SENDER_MAP;
|
||||
}
|
||||
ReloadSenderMapFromDB()
|
||||
{
|
||||
if(!global.START_SERVER)
|
||||
return ;
|
||||
this.SenderMap = {}
|
||||
this.SenderBlockHashMap = {}
|
||||
var EndNum = GetCurrentBlockNumByTime();
|
||||
var StartNum = EndNum - MAX_LENGTH_SENDER_MAP - DELTA_START_SENDER_MAP;
|
||||
if(StartNum < 0)
|
||||
StartNum = 0
|
||||
for(var Num = StartNum; Num < EndNum; Num++)
|
||||
{
|
||||
var Block = this.ReadBlockDB(Num);
|
||||
if(!Block)
|
||||
break;
|
||||
this.AddToSenderMap(Block)
|
||||
}
|
||||
this.WasReloadSenderMapFromDB = 1
|
||||
}
|
||||
ClearOldSenderMapItem()
|
||||
{
|
||||
if(!global.START_SERVER)
|
||||
return ;
|
||||
var MinBlockNum = GetCurrentBlockNumByTime() - (MAX_LENGTH_SENDER_MAP + COUNT_BLOCKS_FOR_LOAD);
|
||||
var ArrForDel = [];
|
||||
for(var key in this.SenderMap)
|
||||
{
|
||||
var ItemArr = this.SenderMap[key];
|
||||
while(ItemArr.length)
|
||||
{
|
||||
var Item = ItemArr[0];
|
||||
if(Item.BlockNum > MinBlockNum)
|
||||
break;
|
||||
ItemArr.shift()
|
||||
}
|
||||
if(ItemArr.length === 0)
|
||||
ArrForDel.push(key)
|
||||
}
|
||||
for(var i = 0; i < ArrForDel.length; i++)
|
||||
{
|
||||
var key = ArrForDel[i];
|
||||
delete this.SenderMap[key]
|
||||
}
|
||||
}
|
||||
};
|
||||
258
Source/core/transfer-msg.js
Normal file
258
Source/core/transfer-msg.js
Normal file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* @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";
|
||||
const MAX_MESSAGE_COUNT = 1000;
|
||||
module.exports = class CMessages extends require("./transaction-validator")
|
||||
{
|
||||
constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual)
|
||||
{
|
||||
super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual)
|
||||
this.MemPoolMsg = []
|
||||
for(var i = 0; i <= MAX_LEVEL_SPECIALIZATION; i++)
|
||||
this.MemPoolMsg[i] = new RBTree(CompareItemTimePow)
|
||||
}
|
||||
AddMsgToQuote(Msg)
|
||||
{
|
||||
var Tree = this.MemPoolMsg[Msg.Level];
|
||||
if(Tree)
|
||||
{
|
||||
if(Tree.insert(Msg))
|
||||
{
|
||||
if(Tree.size > MEM_POOL_MSG_COUNT)
|
||||
{
|
||||
var maxitem = Tree.max();
|
||||
Tree.remove(maxitem)
|
||||
if(maxitem === Msg)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
IsValidMsg(Msg)
|
||||
{
|
||||
this.CheckCreateMsgHASH(Msg)
|
||||
if(Msg.power < MIN_POWER_POW_MSG)
|
||||
return - 1;
|
||||
if(Msg.time > this.CurrentBlockNum)
|
||||
return - 1;
|
||||
return 1;
|
||||
}
|
||||
CheckCreateMsgHASH(Msg)
|
||||
{
|
||||
if(!Msg.HashPow)
|
||||
{
|
||||
Msg.HASH = sha3(Msg.body)
|
||||
Msg.HashPow = GetHashWithValues(Msg.HASH, Msg.nonce, Msg.time)
|
||||
Msg.power = GetPowPower(Msg.HashPow)
|
||||
Msg.TimePow = Msg.time + Msg.power - Math.log2(Msg.body.length / 128)
|
||||
Msg.Level = AddrLevelArr(this.addrArr, Msg.addrArr)
|
||||
if(Msg.Level >= MAX_LEVEL_SPECIALIZATION)
|
||||
Msg.Level = MAX_LEVEL_SPECIALIZATION
|
||||
}
|
||||
}
|
||||
CreateMsgFromBody(Body, ToAddr)
|
||||
{
|
||||
var HASH = sha3(Body);
|
||||
var Msg = {HASH:HASH, body:Body, addrArr:ToAddr, nonce:CreateNoncePOWExtern(HASH, this.CurrentBlockNum, 3 * (1 << MIN_POWER_POW_MSG)),
|
||||
time:this.CurrentBlockNum, };
|
||||
this.CheckCreateMsgHASH(Msg)
|
||||
return Msg;
|
||||
}
|
||||
SendMessage(Body, ToAddr)
|
||||
{
|
||||
var Msg = this.CreateMsgFromBody(Body, ToAddr);
|
||||
this.SendMessageNext(Msg)
|
||||
}
|
||||
SendMessageNext(Msg)
|
||||
{
|
||||
var CountNodes = 3;
|
||||
var LevelStart = Msg.Level;
|
||||
if(CompareArr(this.addrArr, Msg.addrArr) === 0)
|
||||
return false;
|
||||
for(var L = LevelStart; L >= 0; L--)
|
||||
if(this.LevelNodes[L] && this.LevelNodes[L].length)
|
||||
{
|
||||
var arr = this.LevelNodes[L];
|
||||
for(var j = 0; arr && j < arr.length; j++)
|
||||
{
|
||||
var Node = arr[j];
|
||||
this.SendF(Node, {"Method":"MESSAGE", "Data":{Arr:[Msg]}})
|
||||
CountNodes--
|
||||
if(CountNodes <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static
|
||||
MESSAGE_F()
|
||||
{
|
||||
return "{Arr:[{addrArr:hash,body:tr,nonce:uint,time:uint}]}";
|
||||
}
|
||||
MESSAGE(Info, CurTime)
|
||||
{
|
||||
var Data = this.DataFromF(Info);
|
||||
var arr = Data.Arr;
|
||||
for(var i = 0; i < arr.length; i++)
|
||||
{
|
||||
var Msg = arr[i];
|
||||
if(this.IsValidMsg(Msg))
|
||||
{
|
||||
if(CompareArr(this.addrArr, Msg.addrArr) === 0)
|
||||
{
|
||||
var App = DAppByType[Msg.body[0]];
|
||||
if(App)
|
||||
{
|
||||
App.OnMessage(Msg, BlockNum, i)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(this.AddMsgToQuote(Msg) === 1)
|
||||
{
|
||||
this.SendMessageNext(Msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SendGetMessage(Node)
|
||||
{
|
||||
var Context = {"SendGetMessage":1};
|
||||
this.Send(Node, {"Method":"GETMESSAGE", "Context":Context, "Data":undefined})
|
||||
}
|
||||
GETMESSAGE(Info, CurTime)
|
||||
{
|
||||
var arr = [];
|
||||
var BufLength = 300;
|
||||
var Level = AddrLevelArr(this.addrArr, Info.Node.addrArr);
|
||||
var Tree = this.MemPoolMsg[Level];
|
||||
if(Tree)
|
||||
{
|
||||
var it = Tree.iterator(), Item;
|
||||
while((Item = it.next()) !== null)
|
||||
{
|
||||
if(arr.length >= MAX_MESSAGE_COUNT)
|
||||
break;
|
||||
arr.push(Item)
|
||||
BufLength += Item.body.length + 50
|
||||
}
|
||||
}
|
||||
this.SendF(Info.Node, {"Method":"MESSAGE", "Context":Info.Context, "Data":{Arr:arr}}, BufLength)
|
||||
}
|
||||
AddTransaction(Tr, ToAll)
|
||||
{
|
||||
Tr.ToAll = ToAll
|
||||
var Res = this.IsValidTransaction(Tr, this.CurrentBlockNum);
|
||||
if(Res <= 0 && Res !== - 3)
|
||||
return Res;
|
||||
if(Tr.num < this.CurrentBlockNum)
|
||||
return - 3;
|
||||
var delta = Tr.num - this.CurrentBlockNum;
|
||||
if(delta > 3)
|
||||
{
|
||||
if(delta < 15)
|
||||
{
|
||||
let TR = Tr;
|
||||
let SELF = this;
|
||||
setTimeout(function ()
|
||||
{
|
||||
var Res = SELF.AddTransaction(TR, TR.ToAll);
|
||||
if(TR.ToAll)
|
||||
ToLogClient("#3 Added " + TrName(TR) + " for block: " + TR.num + " on timer Res=" + Res)
|
||||
}, (delta - 3) * 1000)
|
||||
if(Tr.ToAll)
|
||||
ToLogClient("#2 Added " + TrName(Tr) + " for block: " + Tr.num + " to timer. Send transaction after " + (delta - 3) + " sec")
|
||||
return 4;
|
||||
}
|
||||
return - 3;
|
||||
}
|
||||
var Block = this.GetBlockContext(Tr.num);
|
||||
if(!Block)
|
||||
return - 5;
|
||||
if(Block.Active)
|
||||
{
|
||||
Res = - 3
|
||||
}
|
||||
else
|
||||
{
|
||||
Res = this.AddTrToBlockQuote(Block, Tr)
|
||||
if(Tr.ToAll)
|
||||
this.SendTransaction(Tr)
|
||||
}
|
||||
ToLogContext("#1 Add " + TrName(Tr) + " for Block: " + Tr.num + " Res=" + Res)
|
||||
return Res;
|
||||
}
|
||||
SendTransaction(Tr)
|
||||
{
|
||||
if(!Tr.ToAll)
|
||||
return ;
|
||||
var CurTime = GetCurrentTime(0) - 0;
|
||||
var Count;
|
||||
if(GrayConnect())
|
||||
Count = Math.trunc(MAX_GRAY_CONNECTIONS_TO_SERVER / 2)
|
||||
else
|
||||
Count = Math.min(this.ActualNodes.size, 16)
|
||||
if(Count < 2)
|
||||
Count = 2
|
||||
var ArrNodes = this.GetActualNodes();
|
||||
for(var i = 0; i < ArrNodes.length; i++)
|
||||
{
|
||||
var Node = ArrNodes[i];
|
||||
if(!Node)
|
||||
continue;
|
||||
if(Node.TaskLastSend)
|
||||
{
|
||||
var Delta = CurTime - Node.TaskLastSend;
|
||||
if(Delta < global.PERIOD_GET_BLOCK || Node.StopGetBlock)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Node.TaskLastSend = CurTime
|
||||
this.SendF(Node, {"Method":"TRANSACTION", "Data":Tr}, Tr.body.length + 1000)
|
||||
ToLogContext("Send " + TrName(Tr) + " to " + NodeName(Node))
|
||||
Count--
|
||||
if(Count <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
static
|
||||
TRANSACTION_F()
|
||||
{
|
||||
return "{body:tr}";
|
||||
}
|
||||
TRANSACTION(Info, CurTime)
|
||||
{
|
||||
var Tr = this.DataFromF(Info);
|
||||
ToLogContext("Receive " + TrName(Tr) + " from " + NodeName(Info.Node))
|
||||
this.AddTransaction(Tr, 0)
|
||||
}
|
||||
};
|
||||
|
||||
function ToLogContext(Str)
|
||||
{
|
||||
};
|
||||
|
||||
function TrName(Tr)
|
||||
{
|
||||
if(!Tr.HASH)
|
||||
SERVER.CheckCreateTransactionObject(Tr);
|
||||
var Str = GetHexFromArr(Tr.HASH);
|
||||
return "Tx:" + Str.substr(0, 8);
|
||||
};
|
||||
global.TrName = TrName;
|
||||
189
Source/core/update.js
Normal file
189
Source/core/update.js
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* @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.RunOnUpdate = RunOnUpdate;
|
||||
|
||||
function RunOnUpdate()
|
||||
{
|
||||
var fname = GetDataPath("DB/update.lst");
|
||||
var UpdateInfo = LoadParams(fname, {UPDATE_NUM_COMPLETE:1071});
|
||||
if(!UpdateInfo.UPDATE_NUM_COMPLETE)
|
||||
UpdateInfo.UPDATE_NUM_COMPLETE = 0;
|
||||
var CurNum = UpdateInfo.UPDATE_NUM_COMPLETE;
|
||||
if(CurNum !== UPDATE_CODE_VERSION_NUM)
|
||||
{
|
||||
UpdateInfo.UPDATE_NUM_COMPLETE = UPDATE_CODE_VERSION_NUM;
|
||||
ToLog("UPDATER Start");
|
||||
SaveParams(fname, UpdateInfo);
|
||||
if(global.TEST_NETWORK || global.LOCAL_RUN)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
ToLog("UPDATER Finish");
|
||||
}
|
||||
};
|
||||
|
||||
function CreateHeadersHash100()
|
||||
{
|
||||
ToLog("CreateHeadersHash100");
|
||||
const DBRow = require("./db/db-row");
|
||||
global.UpdateMode = 1;
|
||||
var DB = SERVER.DBHeader100;
|
||||
var Num = 0;
|
||||
var PrevHash100 = [];
|
||||
while(1)
|
||||
{
|
||||
var Block = SERVER.ReadBlockHeaderDB(Num);
|
||||
if(!Block)
|
||||
break;
|
||||
var Hash100;
|
||||
if(Num === 0)
|
||||
Hash100 = [];
|
||||
else
|
||||
Hash100 = sha3arr2(PrevHash100, Block.Hash);
|
||||
DB.Write({Num:Num / 100, Hash100:Hash100, Hash:Block.Hash});
|
||||
if(Num % 1000000 === 0)
|
||||
ToLog("Create Hash100:" + Num);
|
||||
PrevHash100 = Hash100;
|
||||
Num += 100;
|
||||
}
|
||||
global.UpdateMode = 0;
|
||||
};
|
||||
|
||||
function CheckRewriteTr(Num,StrHash,StartRewrite)
|
||||
{
|
||||
if(SERVER.BlockNumDB < StartRewrite)
|
||||
return "NO";
|
||||
var AccountsHash = DApps.Accounts.GetHashOrUndefined(Num);
|
||||
if(!AccountsHash || GetHexFromArr(AccountsHash) !== StrHash)
|
||||
{
|
||||
ToLog("START REWRITE ERR ACTS TRANSACTIONS");
|
||||
SERVER.ReWriteDAppTransactions(SERVER.BlockNumDB - StartRewrite);
|
||||
return "Rewrite";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "OK";
|
||||
}
|
||||
};
|
||||
|
||||
function CheckRewriteAllTr2(Num,StrHash,Num2,StrHash2)
|
||||
{
|
||||
if(global.LOCAL_RUN || global.TEST_NETWORK)
|
||||
return "NONE";
|
||||
var MaxNum = SERVER.GetMaxNumBlockDB();
|
||||
if(MaxNum < START_BLOCK_ACCOUNT_HASH)
|
||||
return "NONE";
|
||||
var AccountsHash = DApps.Accounts.GetHashOrUndefined(Num);
|
||||
var AccountsHash2 = DApps.Accounts.GetHashOrUndefined(Num2);
|
||||
if(AccountsHash2 && GetHexFromArr(AccountsHash2) === StrHash2)
|
||||
return "OK";
|
||||
if(AccountsHash && GetHexFromArr(AccountsHash) !== StrHash)
|
||||
{
|
||||
ToLog("***************** START REWRITE ALL DAPPS");
|
||||
global.UpdateMode = 1;
|
||||
for(var key in DApps)
|
||||
{
|
||||
DApps[key].ClearDataBase();
|
||||
}
|
||||
global.UpdateMode = 0;
|
||||
return "Rewrite";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "OK";
|
||||
}
|
||||
};
|
||||
|
||||
function CheckRewriteAllTr(Num,StrHash,Num2,StrHash2)
|
||||
{
|
||||
if(global.LOCAL_RUN || global.TEST_NETWORK)
|
||||
return "NONE";
|
||||
var MaxNum = SERVER.GetMaxNumBlockDB();
|
||||
if(MaxNum < START_BLOCK_ACCOUNT_HASH)
|
||||
return "NONE";
|
||||
var AccountsHash = DApps.Accounts.GetHashOrUndefined(Num);
|
||||
if(AccountsHash && GetHexFromArr(AccountsHash) !== StrHash)
|
||||
{
|
||||
ToLog("***************** START REWRITE ALL DAPPS");
|
||||
global.UpdateMode = 1;
|
||||
for(var key in DApps)
|
||||
{
|
||||
DApps[key].ClearDataBase();
|
||||
}
|
||||
global.UpdateMode = 0;
|
||||
return "Rewrite";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "OK";
|
||||
}
|
||||
};
|
||||
global.CheckRewriteTr = CheckRewriteTr;
|
||||
|
||||
function RecreateAccountRest1()
|
||||
{
|
||||
var name = "accounts-rest";
|
||||
var fname = GetDataPath("DB/" + name);
|
||||
if(fs.existsSync(fname))
|
||||
{
|
||||
ToLog("Delete " + fname);
|
||||
fs.unlinkSync(fname);
|
||||
}
|
||||
};
|
||||
|
||||
function RecreateAccountHashDB3()
|
||||
{
|
||||
var name = "accounts-hash2";
|
||||
var fname = GetDataPath("DB/" + name);
|
||||
if(fs.existsSync(fname))
|
||||
{
|
||||
global.UpdateMode = 1;
|
||||
ToLog("Start updating " + name);
|
||||
const DBRow = require("../core/db/db-row");
|
||||
var DB0 = new DBRow(name, 6 + 32 + 32 + 10, "{BlockNum:uint, Hash:hash, SumHash:hash, Reserve: arr10}");
|
||||
var DB3 = DApps.Accounts.DBAccountsHash;
|
||||
for(var num = 0; true; num++)
|
||||
{
|
||||
var Item = DB0.Read(num);
|
||||
if(!Item)
|
||||
break;
|
||||
Item.AccHash = Item.Hash;
|
||||
DB3.Write(Item);
|
||||
}
|
||||
ToLog("Finish updating " + name);
|
||||
DB0.Close();
|
||||
DB3.Close();
|
||||
global.UpdateMode = 0;
|
||||
fs.unlinkSync(fname);
|
||||
}
|
||||
};
|
||||
|
||||
function ReWriteDBSmartWrite()
|
||||
{
|
||||
global.UpdateMode = 1;
|
||||
ToLog("Start ReWriteDBSmartWrite");
|
||||
require("../core/db/db-row");
|
||||
for(var num = 0; true; num++)
|
||||
{
|
||||
var Item = DApps.Smart.DBSmart.Read(num);
|
||||
if(!Item)
|
||||
break;
|
||||
var Body = BufLib.GetBufferFromObject(Item, DApps.Smart.FORMAT_ROW, 20000, {});
|
||||
if(Body.length > 15000)
|
||||
ToLog("Smart " + Item.Num + ". " + Item.Name + " length=" + Body.length);
|
||||
DApps.Smart.DBSmartWrite(Item);
|
||||
}
|
||||
ToLog("Finish ReWriteDBSmartWrite");
|
||||
DApps.Smart.DBSmart.Close();
|
||||
global.UpdateMode = 0;
|
||||
};
|
||||
269
Source/core/wallet.js
Normal file
269
Source/core/wallet.js
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* @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";
|
||||
const fs = require('fs');
|
||||
const crypto = require('crypto');
|
||||
require("./library");
|
||||
require("./crypto-library");
|
||||
const WalletPath = "WALLET";
|
||||
const DBRow = require("./db/db-row");
|
||||
const CONFIG_NAME = GetDataPath(WalletPath + "/config.lst");
|
||||
class CApp
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
CheckCreateDir(GetDataPath(WalletPath))
|
||||
var bReadOnly = (global.PROCESS_NAME !== "TX");
|
||||
this.Password = ""
|
||||
this.WalletOpen = undefined
|
||||
var Params = LoadParams(CONFIG_NAME, undefined);
|
||||
if(!Params)
|
||||
{
|
||||
Params = {}
|
||||
if(global.TEST_NETWORK)
|
||||
{
|
||||
Params.Key = global.ARR_PUB_KEY[0]
|
||||
}
|
||||
else
|
||||
{
|
||||
Params.Key = GetHexFromArr(crypto.randomBytes(32))
|
||||
}
|
||||
Params.AccountMap = {}
|
||||
Params.MiningAccount = 0
|
||||
}
|
||||
if(Params.MiningAccount)
|
||||
global.GENERATE_BLOCK_ACCOUNT = Params.MiningAccount
|
||||
this.AccountMap = Params.AccountMap
|
||||
this.KeyPair = crypto.createECDH('secp256k1')
|
||||
if(Params.Protect)
|
||||
{
|
||||
ToLogClient("Wallet protect by password")
|
||||
this.KeyXOR = GetArrFromHex(Params.KeyXOR)
|
||||
this.WalletOpen = false
|
||||
this.SetPrivateKey(Params.PubKey)
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SetPrivateKey(Params.Key)
|
||||
}
|
||||
}
|
||||
SetMiningAccount(Account)
|
||||
{
|
||||
global.GENERATE_BLOCK_ACCOUNT = Account
|
||||
this.SaveWallet()
|
||||
}
|
||||
AddTransaction(Tr)
|
||||
{
|
||||
if(!global.TX_PROCESS.Worker)
|
||||
return 0;
|
||||
var StrHex = GetHexFromArr(sha3(Tr.body));
|
||||
global.TX_PROCESS.Worker.send({cmd:"FindTX", TX:StrHex})
|
||||
return SERVER.AddTransaction(Tr, 1);
|
||||
}
|
||||
SetPrivateKey(KeyStr, bSetNew)
|
||||
{
|
||||
var bGo = 1;
|
||||
if(this.WalletOpen === false)
|
||||
{
|
||||
bGo = 0
|
||||
}
|
||||
if(KeyStr && KeyStr.length === 64 && bGo)
|
||||
{
|
||||
this.KeyPair.setPrivateKey(GetArr32FromHex(KeyStr))
|
||||
this.KeyPair.PubKeyArr = this.KeyPair.getPublicKey('', 'compressed')
|
||||
this.KeyPair.PubKeyStr = GetHexFromArr(this.KeyPair.PubKeyArr)
|
||||
this.KeyPair.PrivKeyStr = KeyStr.toUpperCase()
|
||||
this.KeyPair.addrArr = this.KeyPair.PubKeyArr.slice(1)
|
||||
this.KeyPair.addrStr = GetHexAddresFromPublicKey(this.KeyPair.addrArr)
|
||||
this.KeyPair.addr = this.KeyPair.addrArr
|
||||
this.KeyPair.WasInit = 1
|
||||
this.PubKeyArr = this.KeyPair.PubKeyArr
|
||||
}
|
||||
else
|
||||
{
|
||||
this.KeyPair.WasInit = 0
|
||||
if(KeyStr)
|
||||
{
|
||||
this.PubKeyArr = GetArrFromHex(KeyStr)
|
||||
this.KeyPair.PubKeyStr = GetHexFromArr(this.PubKeyArr)
|
||||
}
|
||||
else
|
||||
{
|
||||
this.PubKeyArr = []
|
||||
this.KeyPair.PubKeyStr = ""
|
||||
}
|
||||
this.KeyPair.PrivKeyStr = ""
|
||||
}
|
||||
if(bSetNew)
|
||||
{
|
||||
this.AccountMap = {}
|
||||
}
|
||||
this.FindMyAccounts(0)
|
||||
if(bGo)
|
||||
this.SaveWallet()
|
||||
}
|
||||
CloseWallet()
|
||||
{
|
||||
this.Password = ""
|
||||
this.WalletOpen = false
|
||||
this.KeyPair = crypto.createECDH('secp256k1')
|
||||
this.SetPrivateKey(GetHexFromArr(this.PubKeyArr), false)
|
||||
ToLogClient("Wallet close")
|
||||
return 1;
|
||||
}
|
||||
OpenWallet(StrPassword)
|
||||
{
|
||||
if(this.WalletOpen !== false)
|
||||
{
|
||||
ToLogClient("Wallet was open")
|
||||
}
|
||||
var Hash = this.HashProtect(StrPassword);
|
||||
var TestPrivKey = this.XORHash(this.KeyXOR, Hash, 32);
|
||||
if(!IsZeroArr(TestPrivKey))
|
||||
{
|
||||
this.KeyPair.setPrivateKey(Buffer.from(TestPrivKey))
|
||||
var TestPubKey = this.KeyPair.getPublicKey('', 'compressed');
|
||||
if(CompareArr(TestPubKey, this.PubKeyArr) !== 0)
|
||||
{
|
||||
ToLogClient("Wrong password")
|
||||
return 0;
|
||||
}
|
||||
this.Password = StrPassword
|
||||
this.WalletOpen = true
|
||||
this.SetPrivateKey(GetHexFromArr(TestPrivKey), false)
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Password = StrPassword
|
||||
this.WalletOpen = true
|
||||
this.SetPrivateKey(GetHexFromArr(this.PubKeyArr), false)
|
||||
}
|
||||
ToLogClient("Wallet open")
|
||||
return 1;
|
||||
}
|
||||
SetPasswordNew(StrPassword)
|
||||
{
|
||||
if(this.WalletOpen === false)
|
||||
{
|
||||
ToLogClient("Wallet is close by password")
|
||||
return ;
|
||||
}
|
||||
this.Password = StrPassword
|
||||
if(StrPassword)
|
||||
this.WalletOpen = true
|
||||
else
|
||||
this.WalletOpen = undefined
|
||||
this.SaveWallet()
|
||||
}
|
||||
HashProtect(Str)
|
||||
{
|
||||
var arr = shaarr(Str);
|
||||
for(var i = 0; i < 10000; i++)
|
||||
{
|
||||
arr = shaarr(arr)
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
XORHash(arr1, arr2, length)
|
||||
{
|
||||
var arr3 = [];
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
arr3[i] = arr1[i] ^ arr2[i]
|
||||
}
|
||||
return arr3;
|
||||
}
|
||||
SaveWallet()
|
||||
{
|
||||
if(this.WalletOpen === false)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
var Params = {};
|
||||
if(this.Password)
|
||||
{
|
||||
Params.Protect = true
|
||||
var Hash = this.HashProtect(this.Password);
|
||||
if(this.KeyPair.WasInit)
|
||||
{
|
||||
Params.KeyXOR = GetHexFromArr(this.XORHash(this.KeyPair.getPrivateKey(), Hash, 32))
|
||||
}
|
||||
else
|
||||
{
|
||||
var Key2 = [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];
|
||||
Params.KeyXOR = GetHexFromArr(this.XORHash(Key2, Hash, 32))
|
||||
}
|
||||
Params.PubKey = GetHexFromArr(this.PubKeyArr)
|
||||
this.KeyXOR = GetArrFromHex(Params.KeyXOR)
|
||||
}
|
||||
else
|
||||
{
|
||||
if(this.KeyPair.WasInit)
|
||||
Params.Key = this.KeyPair.PrivKeyStr
|
||||
else
|
||||
Params.Key = GetHexFromArr(this.PubKeyArr)
|
||||
}
|
||||
Params.AccountMap = this.AccountMap
|
||||
Params.MiningAccount = global.GENERATE_BLOCK_ACCOUNT
|
||||
SaveParams(CONFIG_NAME, Params)
|
||||
}
|
||||
OnCreateAccount(Data)
|
||||
{
|
||||
this.AccountMap[Data.Num] = 0
|
||||
}
|
||||
FindMyAccounts(bClean)
|
||||
{
|
||||
if(IsZeroArr(this.PubKeyArr))
|
||||
return ;
|
||||
if(bClean)
|
||||
this.AccountMap = {}
|
||||
DApps.Accounts.FindAccounts([this.PubKeyArr], this.AccountMap, 0)
|
||||
}
|
||||
GetAccountKey(Num)
|
||||
{
|
||||
if(this.KeyPair.WasInit && global.TestTestWaletMode)
|
||||
{
|
||||
}
|
||||
return this.KeyPair;
|
||||
}
|
||||
GetPrivateKey(Num)
|
||||
{
|
||||
if(!this.KeyPair.WasInit)
|
||||
return [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];
|
||||
var KeyPair;
|
||||
if(Num)
|
||||
{
|
||||
KeyPair = this.GetAccountKey(Num)
|
||||
}
|
||||
else
|
||||
{
|
||||
KeyPair = this.KeyPair
|
||||
}
|
||||
return KeyPair.getPrivateKey();
|
||||
}
|
||||
GetSignFromArr(Arr, Num)
|
||||
{
|
||||
if(!this.KeyPair.WasInit)
|
||||
return "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
|
||||
var PrivKey = this.GetPrivateKey(Num);
|
||||
var sigObj = secp256k1.sign(SHA3BUF(Arr), Buffer.from(PrivKey));
|
||||
return GetHexFromArr(sigObj.signature);
|
||||
}
|
||||
GetSignTransaction(TR)
|
||||
{
|
||||
if(!this.KeyPair.WasInit)
|
||||
return "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
|
||||
var PrivKey = this.GetPrivateKey(this.AccountMap[TR.FromID]);
|
||||
var Arr = DApps.Accounts.GetSignTransferTx(TR, PrivKey);
|
||||
return GetHexFromArr(Arr);
|
||||
}
|
||||
};
|
||||
global.WALLET = new CApp;
|
||||
Reference in New Issue
Block a user