update code

This commit is contained in:
2019-07-12 20:45:46 +08:00
commit 750a54c15f
131 changed files with 49139 additions and 0 deletions

440
Source/core/base.js Normal file
View 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++;
}
};

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

364
Source/core/buffer.js Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

330
Source/core/constant.js Normal file
View 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;
}
}
}
};

File diff suppressed because it is too large Load Diff

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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

483
Source/core/library.js Normal file
View 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
View 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
View 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
View 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
View 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;
};

View 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

File diff suppressed because it is too large Load Diff

50
Source/core/startlib.js Normal file
View 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);
});

View 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};
};

View 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
View 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
View 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
View 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;