tera/src/core/node.ts

638 lines
21 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* @project: TERA
* @version: Development (beta)
* @license: MIT (not for evil)
* @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com]
* Web: https://terafoundation.org
* Twitter: https://twitter.com/terafoundation
* Telegram: https://t.me/terafoundation
*/
"use strict";
import "./library"
import * as net from "net"
import { secp256k1, RBTree } from '../core/library'
import { TeraSocket, SocketSendInfo } from "../interfaces/server";
var ConnectIDCount = 1;
export default class CNode {
id: number;
addrStr: string
ip: string
port: number
StartFindList: number
WhiteConnect: number
GrayConnect: number
POW: number
FirstTime: number
FirstTimeStr: string
LastTime: number
LastTimeError: number
LastTimeTransfer: number
FromIP: any
FromPort: any
Active: boolean
Hot: boolean
CanHot: boolean
CountChildConnect: number
BlockProcessCount: number
VersionOK: boolean
VersionNum: number
Delete: number
DeltaBan: number
Name: string
Info: string
PrevInfo: string
StartTimeHot: number
NextHotDelta: number
LastTimeGetNode: number
DeltaGlobTime: number
CountDeltaTime: number
DeltaTime: number
SumDeltaTime: number
TransferCount: number
StopGetBlock: number
LevelCount: number
LevelEnum: number
TimeMap: {}
bInit: number
INFO: {
BlockNumDB?: number;
WasPing?: boolean;
LoadHistoryMode?: boolean;
portweb?: number
}
DoubleConnectCount: number
StartTimeConnect: number
NextConnectDelta: number
StartTimeGetNodes: number
NextGetNodesDelta: number
PingStart: number
NextPing: number
SendBlockArr: any[]
LoadBlockArr: any[]
SendBlockCount: number
LoadBlockCount: number
SendBlockCountAll: number
LoadBlockCountAll: number
WantHardTrafficArr: any[]
WantHardTraffic: number
CanHardTraffic: number
BufWriteLength: number
BufWrite: Buffer | Uint8Array
SendPacket: RBTree<SocketSendInfo>
ConnectCount: number
TrafficArr: any[]
SendTrafficCurrent: number
SendTrafficLimit: number
ErrCount: number
ErrCountAll: number
SendPacketNum: number
Socket: TeraSocket
Socket2: TeraSocket
ReconnectFromServer: number
SecretForReconnect: any[] | Buffer
Self: boolean
addrStrTemp: any
DoubleConnection: boolean
PubKey: Buffer
addrArr: any[]
SocketStart: number
WaitConnectFromServer: number
WaitConnectIP: string
Prioritet: any
WasAddToReconnect: number
WasAddToConnect: number
Level: number
SendRestGetHeader: number
TransferBlockNum: number;
CurBlockNum: number;
NoSendTx: any;
VERSIONMAX: any;
LoadHistoryMode: boolean;
portweb: number;
PingNumber: number;
DeltaTimeM: number;
Times: { Arr: number[] };
AvgDelta: number;
IsAddrList: boolean;
КодДляРазработчикаХекс: any;
ip_arrival: string;
port_arrival: number;
TransferSize: number;
TransferBlockNumFix: number;
constructor(addrStr: string, ip: string, port: number) {
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 = global.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;
} as any)
this.ConnectCount = 0
this.TrafficArr = []
this.SendTrafficCurrent = 0
this.SendTrafficLimit = 0
this.ErrCount = 0
this.ErrCountAll = 0
var Prioritet = this.BlockProcessCount;
global.SERVER.SetNodePrioritet(this, Prioritet)
this.SendPacketNum = 0
}
ConnectStatus() {
if (this.Socket)
return GetSocketStatus(this.Socket);
else
return 0;
}
CreateConnect() {
delete global.SERVER.BAN_IP[this.ip]
let NODE = this;
if (NODE.ConnectStatus()) {
if (NODE.ConnectStatus() === 100)
global.SERVER.AddNodeToActive(NODE)
return;
}
global.AddNodeInfo(NODE, "===CreateConnect===")
global.CloseSocket(NODE.Socket, "CreateConnect")
NODE.SocketStart = Date.now()
NODE.Socket = net.createConnection(NODE.port, NODE.ip, function() {
if (NODE.Socket) {
global.socketInit(NODE.Socket, "s")
global.AddNodeInfo(NODE, "OK connected *" + NODE.Socket.ConnectID)
NODE.Socket.ConnectToServer = true
SetSocketStatus(NODE.Socket, 2)
}
}) as TeraSocket
SetSocketStatus(NODE.Socket, 1)
NODE.Socket.Node = NODE
NODE.Socket.ConnectID = "~C" + ConnectIDCount
ConnectIDCount++
this.SetEventsProcessing(NODE.Socket, 0)
}
CreateReconnection() {
let NODE = this;
global.AddNodeInfo(NODE, "===CreateReconnection===")
global.CloseSocket(NODE.Socket2, "CreateReconnection")
NODE.SocketStart = Date.now()
NODE.Socket2 = net.createConnection(NODE.port, NODE.ip, function() {
if (NODE.Socket2) {
global.socketInit(NODE.Socket2, "s")
global.AddNodeInfo(NODE, "OK Reconnected *" + NODE.Socket2.ConnectID)
NODE.Socket2.ConnectToServer = true
SetSocketStatus(NODE.Socket2, 2)
}
}) as TeraSocket
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
global.SERVER.LoadBufSocketList.remove(SocketOld)
global.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 = global.SERVER.GetDataFromBuf(data);
if (Buf) {
var Res = NODE.SendPOWFromClientToServer(SOCKET, Buf.Data);
if (Res) {
return;
}
}
global.CloseSocket(SOCKET, Buf ? "Method=" + Buf.Method : "=CLIENT ON DATA=")
}
else
if (GetSocketStatus(SOCKET) === 3) {
var Buf = global.SERVER.GetDataFromBuf(data);
if (Buf) {
var Str = Buf.Data;
if (Str && Str.substr(0, 24) === "WAIT_CONNECT_FROM_SERVER") {
global.AddNodeInfo(NODE, "2. CLIENT OK POW")
global.CloseSocket(SOCKET, "WAIT_CONNECT_FROM_SERVER")
NODE.WaitConnectFromServer = 1
NODE.WaitConnectIP = NODE.ip
try {
NODE.SecretForReconnect = global.GetArrFromHex(Str.substr(25))
}
catch (e) {
NODE.SecretForReconnect = []
global.ToLog(e)
}
}
else
if (Str === "OK") {
NODE.NextConnectDelta = 1000
SetSocketStatus(SOCKET, 100)
global.AddNodeInfo(NODE, "4. CLIENT OK CONNECT")
if (RECONNECTION) {
if (NODE.Socket)
SetSocketStatus(NODE.Socket, 200)
}
else {
if (!NODE.Active)
global.SERVER.AddNodeToActive(NODE)
}
return;
}
else
if (Str === "SELF") {
NODE.Self = true
}
else
if (Str === "DOUBLE") {
}
else {
global.AddNodeInfo(NODE, "ERROR:" + Str)
}
}
global.CloseSocket(SOCKET, Buf ? "Method=" + Buf.Method + ":" + Str : "=CLIENT ON DATA=")
}
else {
global.socketRead(Socket, data)
global.SERVER.OnGetFromTCP(NODE, Socket, data)
}
})
SOCKET.on('end', function() {
if (GetSocketStatus(SOCKET))
global.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))
global.AddNodeInfo(NODE, "Get socket close *" + SOCKET.ConnectID + " Stat: " + SocketStatistic(SOCKET))
if (!SOCKET.WasClose) {
if (GetSocketStatus(SOCKET) >= 2) {
global.CloseSocket(SOCKET, "GET CLOSE")
}
}
SetSocketStatus(SOCKET, 0)
})
SOCKET.on('error', function(err) {
if (GetSocketStatus(SOCKET) >= 2) {
global.SERVER.AddCheckErrCount(NODE, 1, "ERR##1 : socket")
global.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 = global.BufLib.GetBufferFromObject(Info, global.FORMAT_POW_TO_SERVER, 1200, {});
var BufAll = global.SERVER.GetBufFromData("POW_CONNECT7", BufWrite, 1);
Socket.write(BufAll)
return 1;
}
try {
var Buf = global.BufLib.GetObjectFromBuffer(data, global.FORMAT_POW_TO_CLIENT, {});
} catch (e) {
global.SERVER.SendCloseSocket(Socket, "FORMAT_POW_TO_CLIENT")
return 0;
}
if (global.CompareArr(Buf.addrArr, global.SERVER.addrArr) === 0) {
Node.Self = true
global.AddNodeInfo(Node, "END: SELF")
global.SERVER.SendCloseSocket(Socket, "SELF")
return;
}
var addrStr = global.GetHexFromAddres(Buf.addrArr);
if (!Node.StartFindList && addrStr !== Node.addrStr) {
global.AddNodeInfo(Node, "END: CHANGED ADDR: " + Node.addrStr.substr(0, 16) + "->" + addrStr.substr(0, 16))
global.SERVER.SendCloseSocket(Socket, "ADDRESS_HAS_BEEN_CHANGED")
return;
}
if (Node.addrStrTemp) {
global.AddNodeInfo(Node, "Set Addr = " + addrStr)
Node.addrStr = addrStr
global.SERVER.CheckNodeMap(Node)
}
var Result = false;
if (Buf.PubKeyType === 2 || Buf.PubKeyType === 3) {
Result = secp256k1.verify(Buffer.from(global.shaarr(addrStr)), Buffer.from(Buf.Sign), Buffer.from([Buf.PubKeyType].concat(Buf.addrArr)))
if (!Result) {
Result = secp256k1.verify(Buffer.from(global.sha3(addrStr)), Buffer.from(Buf.Sign), Buffer.from([Buf.PubKeyType].concat(Buf.addrArr)))
}
}
if (!Result) {
global.ToLog("END: ERROR_SIGN_SERVER ADDR: " + addrStr.substr(0, 16) + " from ip: " + Socket.remoteAddress)
global.AddNodeInfo(Node, "END: ERROR_SIGN_SERVER ADDR: " + addrStr.substr(0, 16) + " from ip: " + Socket.remoteAddress)
global.SERVER.SendCloseSocket(Socket, "ERROR_SIGN_SERVER")
return;
}
if (Buf.MIN_POWER_POW_HANDSHAKE > 1 + global.MIN_POWER_POW_HANDSHAKE) {
global.ToLog("END: BIG_MIN_POWER_POW_HANDSHAKE ADDR: " + addrStr.substr(0, 16) + " from ip: " + Socket.remoteAddress)
return 0;
}
var TestNode = global.SERVER.NodesMap[addrStr];
if (TestNode && TestNode !== Node) {
if (GetSocketStatus(TestNode.Socket)) {
global.AddNodeInfo(Node, "DoubleConnection find")
Node.DoubleConnection = true
return 0;
}
else {
global.AddNodeInfo(Node, "DoubleConnection find")
TestNode.DoubleConnection = true
}
}
Node.PubKey = Buffer.from([Buf.PubKeyType].concat(Buf.addrArr))
Node.addrArr = Buf.addrArr
Node.addrStr = addrStr
if (global.CompareArr(global.SERVER.addrArr, Node.addrArr) === 0) {
Node.Self = true
return 0;
}
var Hash = global.shaarr2(Buf.addrArr, Buf.HashRND);
var nonce = global.CreateNoncePOWExternMinPower(Hash, 0, Buf.MIN_POWER_POW_HANDSHAKE);
var Info;
if (global.WALLET.WalletOpen && global.IsDeveloperAccount(global.WALLET.PubKeyArr)) {
Info = this.GetPOWClientData(0)
Info.Reconnect = 255
Info.Sign = secp256k1.sign(global.SHA3BUF(Hash), global.WALLET.KeyPair.getPrivateKey('')).signature
Result = global.CheckDevelopSign(Hash, Info.Sign)
if (!Result) {
throw "ERROR DEVELOPSIGN!";
}
}
else {
Info = this.GetPOWClientData(nonce)
Info.PubKeyType = global.SERVER.PubKeyType
Info.Sign = secp256k1.sign(Buffer.from(Hash), global.SERVER.KeyPair.getPrivateKey('')).signature
}
var BufWrite = global.BufLib.GetBufferFromObject(Info, global.FORMAT_POW_TO_SERVER, 1200, {});
var BufAll = global.SERVER.GetBufFromData("POW_CONNECT6", BufWrite, 1);
Socket.write(BufAll)
return 1;
}
GetPOWClientData(nonce) {
var Node = this;
var Info: any = {};
Info.DEF_NETWORK = global.GetNetworkName()
Info.DEF_VERSION = global.DEF_VERSION
Info.DEF_CLIENT = global.DEF_CLIENT
Info.addrArr = global.SERVER.addrArr
Info.ToIP = Node.ip
Info.ToPort = Node.port
Info.FromIP = global.SERVER.ip
Info.FromPort = global.SERVER.port
Info.nonce = nonce
Info.Reconnect = 0
Info.SendBytes = 0
Info.SecretForReconnect = []
Info.Reserv = []
if (global.GrayConnect())
Info.GrayConnect = 1
return Info;
}
write(BufWrite) {
if (!this.Socket)
return;
global.socketWrite(this.Socket, BufWrite)
try {
this.Socket.write(BufWrite)
}
catch (e) {
global.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)
global.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)) {
global.ToLogTrace("===================ERROR=================== " + Status);
return;
}
if (Status === 100 && Socket.Node)
Socket.Node.LastTime = global.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 > global.MAX_WAIT_PERIOD_FOR_STATUS) {
global.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 (global.LOCAL_RUN)
return "" + Node.port;
else {
return "" + Node.ip + ":" + Node.addrStr.substr(0, 6);
}
};
function FindNodeByAddr(Addr, bConnect) {
var Node = global.SERVER.NodesMap[Addr.trim()];
if (Node && Node.ConnectStatus() === 100)
return Node;
if (Node && bConnect) {
Node.NextConnectDelta = 1000;
global.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 = global.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;