tera/Source/core/node.js

616 lines
19 KiB
JavaScript

/*
* @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.LevelsBit = 0
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 && typeof Str === "string" && 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;