/* * @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 CBlock from './block-loader' import { RBTree } from './library' import { STreeBuffer } from './base'; import { teraManager } from '../rpc/manager' require('./library'); require('./crypto-library'); const TX_PROCESS_TIME = 100; const TX_DELTA_PROCESS_TIME = 300; global.CAN_START = false; global.StrWarn = ""; global.SUM_LIST_LENGTH = 2 * global.BLOCK_PROCESSING_LENGTH; global.CONSENSUS_TIK_TIME = global.CONSENSUS_PERIOD_TIME / 10; global.CONSENSUS_CHECK_TIME = global.CONSENSUS_PERIOD_TIME / 20; const PERIOD_FOR_NEXT_SEND = global.CONSENSUS_TIK_TIME * 3; global.BLOCK_DELTA_ACTIVATE = 0; global.TIME_END_EXCHANGE = - 3; global.TIME_START_POW = - 4; global.TIME_START_SAVE = - 4; global.TIME_START_LOAD = global.TIME_START_SAVE - 4; var FORMAT_DATA_TRANSFER = "{\ Version:uint16,\ BlockNum:uint,\ Reserv1:uint32,\ MaxPOW:[{BlockNum:uint,AddrHash:hash,SeqHash:hash}],\ Reserv2:uint32,\ BaseBlockNum:uint,\ MaxSumID:[{BlockNum:uint,SumHash:hash,SumListID:[uint16]}],\ BlockList:[{ID:uint16, AddrHash:hash,SeqHash:hash}],\ TicketArray:[{HashTicket:arr10}],\ TxArray:[{body:tr}],\ NoSendTx:uint,\ }"; const WorkStructSend = {}; export default class CConsensus extends CBlock { CurrentBlockNum SendBlockID RelayMode TreeSendPacket idBlockChainTimer OwnBlockCount LevelNodes constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) { super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) this.CurrentBlockNum = 0 this.SendBlockID = 0 this.RelayMode = false this.TreeSendPacket = new RBTree(global.CompareItemHash) if (!global.ADDRLIST_MODE && !this.VirtualMode) { this.idBlockChainTimer = setInterval(this.StartBlockChain.bind(this), global.CONSENSUS_PERIOD_TIME - 5) setInterval(this.DoTransfer.bind(this), global.CONSENSUS_CHECK_TIME) } } StartBlockChain() { this.OnStartSecond() var CurTimeNum = global.GetCurrentTime() - global.CONSENSUS_PERIOD_TIME / 2; var StartTimeNum = Math.floor((CurTimeNum + global.CONSENSUS_PERIOD_TIME) / global.CONSENSUS_PERIOD_TIME) * global.CONSENSUS_PERIOD_TIME; var DeltaForStart = StartTimeNum - CurTimeNum; if (DeltaForStart < (global.CONSENSUS_PERIOD_TIME - 5)) { var self = this; if (self.idBlockChainTimer) clearInterval(self.idBlockChainTimer) self.idBlockChainTimer = 0 setTimeout(function() { self.idBlockChainTimer = setInterval(self.StartBlockChain.bind(self), global.CONSENSUS_PERIOD_TIME) self.OnStartSecond() }, DeltaForStart) } } OnStartSecond() { global.PrepareStatEverySecond() this.AddStatOnTimer() this.DoBlockChain() } CreateBlockContext() { var Context: any = {}; Context.AddInfo = global.AddInfoBlock.bind(Context) Context.Active = false Context.TransferFromAddr = {} Context.LevelsTransfer = [] Context.ErrRun = "" Context.PowTxTree = new RBTree(global.CompareItemTimePow) Context.PowTicketTree = new RBTree(global.CompareItemTimePow) Context.bSave = false Context.PrevHash = undefined Context.TreeHash = undefined Context.MaxPOW = {} Context.MaxSum = {} Context.SumPow = 0 Context.Power = 0 Context.TrCount = 0 Context.TrDataPos = 0 Context.TrDataLen = 0 Context.Info = "Create at:" + global.GetStrOnlyTimeUTC() var Transfer; var TransferM2; var LocalLevel = 0; var Levels = this.LevelNodes; for (let L = 0; L < Levels.length; L++) { var arr = Levels[L]; if (arr && arr.length > 0) { Transfer = { LocalLevel: LocalLevel, TreeLevel: L, SendCount: 0, GetCount: 0, TransferNodes: {}, WasGet: false, WasSend: false, MustDeltaTime: global.CONSENSUS_TIK_TIME * (2 + global.MAX_LEVEL_SPECIALIZATION - L), } LocalLevel++ Context.LevelsTransfer.push(Transfer) Context.StartLevel = Context.LevelsTransfer.length - 1 for (let j = 0; j < arr.length; j++) { var Node = arr[j]; var Addr = Node.addrStr; if (!Transfer.TransferNodes[Addr]) { let Item = { Node: Node, SendCount: 0, GetCount: 0, addrStr: Addr, TreeLevel: L, GetTiming: 3 * global.CONSENSUS_PERIOD_TIME, }; Transfer.TransferNodes[Addr] = Item } Context.TransferFromAddr[Addr] = Transfer } } } Context.MLevelSend = Context.StartLevel return Context; } StartConsensus() { if (!global.CAN_START) return; var StartBlockNum = global.GetCurrentBlockNumByTime(); if (StartBlockNum < global.BLOCK_PROCESSING_LENGTH2) return; this.CurrentBlockNum = StartBlockNum var Block0 = this.GetBlockContext(StartBlockNum - global.BLOCK_DELTA_ACTIVATE); if (!Block0.Active) { global.AddInfoBlock(Block0, "Activate") this.StartBlock(Block0) } else { global.AddInfoBlock(Block0, "Was Active") } } TrToInfo(Block, Array, StrInfo) { var Str = ""; for (var i = 0; i < Array.length; i++) { var Item = Array[i]; this.CheckCreateTransactionObject(Item) Str += this.GetStrFromHashShort(global.shaarr(Item.body)) + "(" + Item.body.length + ")," } global.AddInfoBlock(Block, "" + StrInfo + ": Arr=[" + Str + "]") } TRANSFER(Info, CurTime) { var startTime = process.hrtime(); var Data = this.DataFromF(Info); var Node = Info.Node; Node.TransferBlockNum = Data.BlockNum Node.CurBlockNum = Data.BaseBlockNum + Data.BlockNum if (Data.Version !== 5) return; var Block = this.GetBlockContext(Data.BlockNum); if (!Block || Block.StartLevel === undefined) { global.ADD_TO_STAT("TRANSFER_ERR_STARTLEVEL") this.AddCheckErrCount(Node, 1, "Err GetBlockContext") return; } if (!Block.Active) this.StartBlock(Block) var Key = Node.addrStr; var Transfer = Block.TransferFromAddr[Key]; if (!Transfer) { global.ADD_TO_STAT("NO_TRANSFER") this.AddCheckErrCount(Node, 1, "Err Transfer") return; } Transfer.WasGet = true if (global.DoTxLog && Data.TicketArray.length) global.ToLog("TRANSFER BlockNum:" + Block.BlockNum + " TicketArray=" + Data.TicketArray.length + " from " + global.NodeName(Node)) if (global.DoTxLog && Data.TxArray.length) global.ToLog("TRANSFER BlockNum:" + Block.BlockNum + " TxArray=" + Data.TxArray.length + " from " + global.NodeName(Node)) this.ToMaxPOWList(Data.MaxPOW) this.ToMaxSumList(this.GetMaxSumListFromID(Node, Data.MaxSumID, Data.BlockList)) var WasNewAdd = 0; if (Data.TxArray.length) { for (var i = 0; i < Data.TxArray.length; i++) { var Tr = Data.TxArray[i]; var Res = this.AddTrToBlockQuote(Block, Tr); if (Res === 1) { WasNewAdd = 1 } if (global.USE_CHECK_SENDING && Res > 0) { var Tt = Block.PowTxTree.find(Tr); if (Tt) { if (!Tt.NodesList) Tt.NodesList = [] Tt.NodesList.push(Node) Tt.TreeLevel = Transfer.TreeLevel } } } } else { for (var i = 0; i < Data.TicketArray.length; i++) { var Tr = this.AddTicketToBlockQuote(Block, Data.TicketArray[i]); if (Tr) { if (!Tr.NodesList) Tr.NodesList = [] Tr.NodesList.push(Node) } } } global.ADD_TO_STAT_TIME("TRANSFER_MS", startTime) var Delta = Date.now() - this.StartLoadBlockTime; if (Delta > 10 * 1000 && Node.TransferCount > 10) { Node.BlockProcessCount++ Node.NextHotDelta = 10 * 1000 } Node.TransferCount++ Node.LastTimeTransfer = global.GetCurrentTime() - 0 var Item = Transfer.TransferNodes[Key]; Item.GetTiming = global.GetCurrentTime(Block.DELTA_CURRENT_TIME) - Block.StartTimeNum if (!Block.TransferNodesCount) Block.TransferNodesCount = 0 Block.TransferNodesCount++ } DoTransfer() { if (global.glStopNode) return; if (!global.CAN_START) return; var MaxPOWList; var MaxSumList; var start = this.CurrentBlockNum - global.BLOCK_PROCESSING_LENGTH; var finish = this.GetLastCorrectBlockNum(); for (var b = start; b <= finish; b++) { var Block = this.GetBlock(b); if (!Block) continue; if (Block.StartLevel === undefined || Block.MLevelSend === undefined) continue; if (!Block.Active) continue; if (global.USE_TICKET) this.DoJobListTX(Block) if (Block.MLevelSend < 0) { this.CheckEndExchange(Block) continue; } if (Block.EndExchange) continue; var Transfer = Block.LevelsTransfer[Block.MLevelSend]; if (!Transfer.WasSend) { if (!MaxPOWList) { MaxPOWList = this.GetMaxPOWList() MaxSumList = this.GetMaxSumList() } var ArrT; if (global.USE_TICKET) ArrT = this.GetArrayFromTicketTree(Block) else ArrT = this.GetArrayFromTxTree(Block) this.SendDataTransfer(Transfer, ArrT, MaxPOWList, MaxSumList, Block) } Transfer.WasSend = true var bNext = Transfer.WasGet; if (!bNext) { var CurTimeNum = global.GetCurrentTime(Block.DELTA_CURRENT_TIME) - 0; var DeltaTime = CurTimeNum - Block.StartTimeNum; if (DeltaTime > Transfer.MustDeltaTime) { bNext = true Block.ErrRun = "" + Transfer.LocalLevel + " " + Block.ErrRun for (var Addr in Transfer.TransferNodes) { var Item = Transfer.TransferNodes[Addr]; global.ADD_TO_STAT("TRANSFER_TIME_OUT") this.AddCheckErrCount(Item.Node, 1, "TRANSFER_TIME_OUT") } global.ADD_TO_STAT("TimeOutLevel") } } if (bNext) { if (Block.MLevelSend === 0) { Block.EndExchangeTime = Date.now() if (!global.USE_TICKET) this.CheckEndExchange(Block) } Block.MLevelSend-- } } } CheckEndExchange(Block) { if (Block.EndExchange) return; if (!global.USE_TICKET) { this.CreateTreeHash(Block) return; } if (!Block.JobListTX || !Block.EndExchangeTime) return; var CurTime = Date.now(); var Delta = CurTime - Block.EndExchangeTime; if (Delta >= TX_DELTA_PROCESS_TIME * 2) { if (global.DoTxLog) global.ToLog("END:" + Block.BlockNum + " -> CreateTreeHash") this.CreateTreeHash(Block) } } SendDataTransfer(Transfer, ArrT, MaxPOWList, MaxSumList, Block) { for (var Addr in Transfer.TransferNodes) { var Item = Transfer.TransferNodes[Addr]; Transfer.SendCount++ var arrPow = []; for (var i = 0; i < MaxPOWList.length; i++) { var elem = MaxPOWList[i]; var Str = "POW:" + Item.Node.id + elem.BlockNum + "-" + global.GetHexFromArr(elem.AddrHash); var bWasSend = global.TreeBlockBuf.LoadValue(Str, 1); if (!bWasSend) { global.TreeBlockBuf.SaveValue(Str, true) arrPow.push(elem) } } var arrSum = []; for (var i = 0; i < MaxSumList.length; i++) { var elem = MaxSumList[i]; var Str = "MAX:" + Item.Node.id + elem.BlockNum + "-" + global.GetHexFromArr(elem.SumHash); var bWasSend = global.TreeBlockBuf.LoadValue(Str, 1); if (!bWasSend) { global.TreeBlockBuf.SaveValue(Str, true) arrSum.push(elem) } } var Arr; if (global.USE_CHECK_SENDING) Arr = this.FilterArrForSendNode(Block, Item.Node, ArrT, global.USE_TICKET) else Arr = ArrT if (global.USE_LEVEL_WAY) { var Arr2 = []; for (var t = 0; t < Arr.length; t++) { var Tr = Arr[t]; if (Tr.TreeLevel !== Transfer.TreeLevel) Arr2.push(Tr) } Arr = Arr2 } if (global.DoTxLog) global.ToLog("SEND TRANSFER BlockNum:" + Block.BlockNum + " Arr=" + Arr.length + " to " + global.NodeName(Item.Node)) var BufData = this.CreateTransferBuffer(Arr, arrPow, arrSum, Block, Item.Node); this.Send(Item.Node, { "Method": "TRANSFER", "Context": {}, "Data": BufData }, 1) if (!Block.JobListTX) Block.JobListTX = [] Block.JobListTX.push({ Node: Item.Node, TreeLevel: Item.TreeLevel, Time: Date.now() }) } } Send(Node, Info, TypeData?) { // defiend in server.ts } TRANSFERTX(Info, CurTime) { var Data = this.DataFromF(Info); var Node = Info.Node; var Block = this.GetBlockContext(Data.BlockNum); if (!Block) { return; } if (global.DoTxLog) global.ToLog("TRANSFERTX BlockNum:" + Block.BlockNum + " Array=" + Data.Array.length + " from " + global.NodeName(Node)) for (var i = 0; i < Data.Array.length; i++) { this.AddTrToBlockQuote(Block, Data.Array[i], 1) } } static TRANSFERTX_F() { return "{BlockNum:uint, Array:[{body:tr}]}"; } static GETTRANSFERTX_F() { return "{BlockNum:uint, TicketArray:[{HashTicket:arr10}]}"; } GETTRANSFERTX(Info, CurTime) { return; var Data = this.DataFromF(Info); var Node = Info.Node; var Block = this.GetBlockContext(Data.BlockNum); if (!Block) { return; } this.SendTrByTickets(Info, Node, Block, Data.TicketArray, 10) } CanSendTest() { return 1; } SendTrByTickets(Info, Node, Block, ArrTT, CountTrySend) { if (!Block.PowTxTree) return; var Arr = []; var bFindTT = 0; var BufLength = 0; for (var i = 0; i < ArrTT.length; i++) { var Tr = ArrTT[i]; this.CheckCreateTicketObject(Tr, Block.BlockNum) var Tr0 = Block.PowTxTree.find(Tr); if (Tr0) { if (Tr0.IsTx) { if (this.CanSendTest()) Arr.push(Tr0) BufLength += Tr0.body.length if (BufLength > global.MAX_BLOCK_SIZE) break; } else { bFindTT = 1 } } } if (bFindTT && CountTrySend) { let SELF = this; setTimeout(function() { SELF.SendTrByTickets(Info, Node, Block, ArrTT, CountTrySend - 1) }, 100) return; } if (!Arr.length) return; var SendData = { "Method": "RETTRANSFERTX", "Context": Info.Context, "Data": { BlockNum: Block.BlockNum, Array: Arr, } }; this.SendF(Node, SendData, global.MAX_BLOCK_SIZE + 1000) } static RETTRANSFERTX_F() { return "{BlockNum:uint,Array:[{body:tr}]}"; } RETTRANSFERTX(Info, CurTime) { return; var Data = this.DataFromF(Info); var Node = Info.Node; Node.TransferBlockNum = Data.BlockNum var Block = this.GetBlockContext(Data.BlockNum); if (!Block || !Block.PowTxTree) { return; } if (global.DoTxLog) global.ToLog("RETTRANSFERTX BlockNum:" + Block.BlockNum + " Array=" + Data.Array.length + " from " + global.NodeName(Node)) for (var i = 0; i < Data.Array.length; i++) { var Tr = Data.Array[i]; this.CheckCreateTransactionObject(Tr) var Tr0 = Block.PowTxTree.find(Tr); if (Tr0) { if (!Tr0.IsTx) { Tr0.IsTx = 1 Tr0.body = Tr.body Tr0.HASH = Tr.HASH } } } } DoJobListTX(Block) { if (Block.EndExchange || !Block.JobListTX || !Block.PowTicketTree) return; var ArrTx; var CurTime = Date.now(); for (var i = 0; i < Block.JobListTX.length; i++) { var JobItem = Block.JobListTX[i]; var Delta = CurTime - JobItem.Time; if (!JobItem.WasSend && Delta >= TX_DELTA_PROCESS_TIME) { JobItem.WasSend = 1 if (!ArrTx) ArrTx = this.GetArrayFromTxTree(Block) var Arr = this.FilterArrForSendNode(Block, JobItem.Node, ArrTx); if (!Arr.length) return; if (global.DoTxLog) global.ToLog("DoJobListTX BlockNum:" + Block.BlockNum + " Arr=" + Arr.length + " to " + global.NodeName(JobItem.Node)) var SendData = { "Method": "TRANSFERTX", "Context": {}, "Data": { BlockNum: Block.BlockNum, Array: Arr, } }; this.SendF(JobItem.Node, SendData, global.MAX_BLOCK_SIZE + 1000) } } } FindNodeTicket(Block, Tr, Node, bTt) { var Ticket; if (bTt) Ticket = Tr else Ticket = Block.PowTicketTree.find(Tr) if (Ticket && Ticket.NodesList) { for (var n = 0; n < Ticket.NodesList.length; n++) { var NodeItem = Ticket.NodesList[n]; if (NodeItem === Node) { return 1; } } } return 0; } FilterArrForSendNode(Block, Node, ArrTx, bTt?) { var Arr = []; for (var t = 0; t < ArrTx.length; t++) { var Tr = ArrTx[t]; if (this.FindNodeTicket(Block, Tr, Node, bTt)) continue; Arr.push(Tr) } return Arr; } CheckEndExchange00(Block) { if (Block.EndExchange) return; var CurTime = Date.now(); var CanEnd = 1; var bSend = 0; var it = Block.PowTxTree.iterator(), Tr; while ((Tr = it.next()) !== null) { if (!Tr.IsTx) { if (!Tr.LastProcessTime) throw "!Tr.LastProcessTime"; var Delta = CurTime - Tr.LastProcessTime; if (Delta < TX_PROCESS_TIME * 10) { bSend = 1 CanEnd = 0 break; } else { var Stop = 1; } } } if (CanEnd) { if (global.DoTxLog) global.ToLog("END:" + Block.BlockNum + " -> CreateTreeHash") this.CreateTreeHash(Block) } else if (bSend) { this.CheckTxExchange(Block, bSend) } } CheckTxExchange(Block, b?) { return; if (Block.EndExchange) return; if (!Block.PowTxTree) return; var CurTime = Date.now(); var ArrNodesArr = []; var it = Block.PowTxTree.iterator(), Tr; while ((Tr = it.next()) !== null) { if (!Tr.IsTx) { if (!Tr.LastProcessTime) throw "!Tr.LastProcessTime"; var Delta = CurTime - Tr.LastProcessTime; if (Delta >= TX_PROCESS_TIME) { for (var i = 0; i < Tr.Nodes.length; i++) { var TrNode = Tr.Nodes[i]; var LocDelta = CurTime - TrNode.Time; if (!TrNode.WasSend && LocDelta >= TX_PROCESS_TIME) { var FindArr = undefined; for (var n = 0; n < ArrNodesArr.length; n++) { var ElArr = ArrNodesArr[n]; if (ElArr.Node === TrNode.Node) { FindArr = ElArr break; } } if (!FindArr) { FindArr = { Node: TrNode.Node, Arr: [] } ArrNodesArr.push(FindArr) } Tr.LastProcessTime = CurTime TrNode.WasSend = 1 FindArr.Arr.push(Tr) break; } } } } } for (var n = 0; n < ArrNodesArr.length; n++) { var ElArr = ArrNodesArr[n]; if (global.DoTxLog) global.ToLog("CheckTxExchange BlockNum:" + Block.BlockNum + " Array=" + ElArr.Arr.length + " to " + global.NodeName(ElArr.Node)) var SendData = { "Method": "GETTRANSFERTX", "Context": {}, "Data": { BlockNum: Block.BlockNum, TicketArray: ElArr.Arr, } }; this.SendF(ElArr.Node, SendData, ElArr.Arr.length * global.TR_TICKET_HASH_LENGTH + 1000) } } GetMaxSumListFromID(Node, MaxSumID, BlockList) { var Str0 = "GETBL:" + Node.id; for (var i = 0; i < BlockList.length; i++) { var elemBlockList = BlockList[i]; global.TreeBlockBuf.SaveValue(Str0 + elemBlockList.ID, elemBlockList) } var MaxSum = []; MaxSum: for (var i = 0; i < MaxSumID.length; i++) { var elem = MaxSumID[i]; var Arr = []; for (var n = 0; n < elem.SumListID.length; n++) { var elemBlockList = global.TreeBlockBuf.LoadValue(Str0 + elem.SumListID[n], 1); if (elemBlockList === undefined) { continue MaxSum; } Arr.push(elemBlockList) } elem.SumList = Arr MaxSum.push(elem) } return MaxSum; } CreateTransferBuffer(ArrT, MaxPOWList, MaxSumList, Block, Node) { var Data; var MaxSumID = []; var BlockList = []; for (var i = 0; i < MaxSumList.length; i++) { var elem0 = MaxSumList[i]; var ArrID = []; for (var n = 0; n < elem0.SumList.length; n++) { var elemBlockList = elem0.SumList[n]; var Str = "BL:" + Node.id + global.GetHexFromArr(elemBlockList.Hash3); var ID = global.TreeBlockBuf.LoadValue(Str, 1); if (ID === undefined) { this.SendBlockID++ ID = this.SendBlockID % 65535 global.TreeBlockBuf.SaveValue(Str, ID) elemBlockList.ID = ID BlockList.push(elemBlockList) } ArrID.push(ID) } MaxSumID.push({ BlockNum: elem0.BlockNum, SumHash: elem0.SumHash, SumListID: ArrID }) } var ArrTt, ArrTx; if (global.USE_TICKET) { ArrTt = ArrT ArrTx = [] } else { ArrTt = [] ArrTx = ArrT } Data = { "Version": 5, "BlockNum": Block.BlockNum, "Reserv1": 0, "MaxPOW": MaxPOWList, "Reserv2": 0, "BaseBlockNum": this.CurrentBlockNum - Block.BlockNum, "MaxSumID": MaxSumID, "BlockList": BlockList, "TicketArray": ArrTt, "TxArray": ArrTx, "NoSendTx": Node.NoSendTx, } var BufWrite = global.BufLib.GetBufferFromObject(Data, FORMAT_DATA_TRANSFER, global.MAX_BLOCK_SIZE + 30000, WorkStructSend); return BufWrite; } static TRANSFER_F() { return FORMAT_DATA_TRANSFER; } CheckingMaxPowOther(Block) { var POW = Block.MaxPOW; if (POW && POW.Hash && global.CompareArr(POW.PowHash, Block.PowHash) < 0) { var LoadBlockNum = Block.BlockNum; var LoadHash = POW.Hash; var StrKey = this.GetStrFromHashShort(LoadHash); var StrHashWas = this.GetStrFromHashShort(Block.Hash); this.StartLoadBlockHeader(LoadHash, LoadBlockNum, "START OTHER:" + StrKey + " WAS:" + StrHashWas, false) global.AddInfoBlock(Block, "REQ H: " + StrKey) } Block.CheckMaxPow = true } AddToMaxPOW(Block, item, Node?) { if (Block && item) { if (!Block.MaxPOW) Block.MaxPOW = {} var POW = Block.MaxPOW; if (!Block.PrevHash) return; item.BlockNum = Block.BlockNum item.PrevHash = Block.PrevHash global.CalcHashBlockFromSeqAddr(item, Block.PrevHash, global.MINING_VERSION_NUM) if (POW.SeqHash === undefined || global.CompareArr(item.PowHash, POW.PowHash) < 0) { POW.AddrHash = item.AddrHash POW.Hash = item.Hash POW.PowHash = item.PowHash POW.PrevHash = item.PrevHash POW.TreeHash = item.TreeHash POW.SeqHash = item.SeqHash } if (Block.SeqHash && global.CompareArr(item.SeqHash, Block.SeqHash) === 0) { if (POW.LocalSeqHash === undefined || global.CompareArr(POW.LocalSeqHash, Block.SeqHash) !== 0 || global.CompareArr(item.PowHash, POW.PowLocalHash) < 0) { POW.LocalAddrHash = item.AddrHash POW.PowLocalHash = item.PowHash POW.LocalSeqHash = Block.SeqHash } } var wasLider; if (POW.MaxTree) wasLider = POW.MaxTree.min() this.AddPOWToMaxTree(POW, item) if (wasLider) { var newLider = POW.MaxTree.min(); if (newLider !== wasLider) { var Power = global.GetPowPower(newLider.PowHash); global.AddInfoBlock(Block, "MaxPOW: " + Power) } } } } AddPOWToMaxTree(POW, item) { if (!POW.MaxTree) { POW.MaxTree = new RBTree(function(a: any, b: any) { return global.CompareArr(a.PowHash, b.PowHash); }) } if (!POW.MaxTree.find(item)) { POW.MaxTree.insert(item) if (POW.MaxTree.size > 12) { var maxitem = POW.MaxTree.max(); POW.MaxTree.remove(maxitem) } } } GetMaxPOWList() { var arr = []; var start, finish; start = this.CurrentBlockNum + global.TIME_START_SAVE - 2 finish = this.CurrentBlockNum for (var b = start; b < finish; b++) { var Block = this.GetBlock(b); if (Block && Block.Prepared && Block.MaxPOW) { if (Block.MaxPOW && Block.MaxPOW.MaxTree) { this.RecreateMaxPOW(Block) var it = Block.MaxPOW.MaxTree.iterator(), Item; while ((Item = it.next()) !== null) { arr.push(Item) } } } } return arr; } ToMaxPOWList(Arr) { for (var i = 0; i < Arr.length; i++) { var item = Arr[i]; if (item && item.BlockNum >= this.CurrentBlockNum - global.BLOCK_PROCESSING_LENGTH && item.BlockNum < this.CurrentBlockNum) { var Block = this.GetBlock(item.BlockNum); this.AddToMaxPOW(Block, item) } } } RecreateMaxPOW(Block) { if (Block.MaxPOW && Block.MaxPOW.MaxTree) { var Tree = Block.MaxPOW.MaxTree; var it = Tree.iterator(), Item; while ((Item = it.next()) !== null) { if (!Item.PrevHash) global.ToLog("NO Item.PrevHash in " + Block.BlockNum) if (Item.PrevHash && global.CompareArr(Item.PrevHash, Block.PrevHash) !== 0) { Tree.remove(Item) it = Tree.iterator() } } } Block.CheckMaxSum = false } CheckMaxSum(Block) { var POW = Block.MaxSum; var List = this.GetBlockList(Block.BlockNum); var SumPow = this.GetSumFromList(List, Block.BlockNum); if (POW && POW.SumHash && POW.SumPow > SumPow) { var LoadBlockNum = Block.BlockNum; var LoadHash = POW.SumHash; var StrKey = this.GetStrFromHashShort(LoadHash); if (this.StartLoadBlockHeader(LoadHash, LoadBlockNum, "START POW:" + POW.SumPow + ">" + SumPow + " SH:" + StrKey, true)) global.AddInfoBlock(Block, "REQ SH: " + StrKey) } Block.CheckMaxSum = true } AddToMaxSum(Block, item) { if (Block && item) { if (!Block.MaxSum) Block.MaxSum = {} var POW = Block.MaxSum; var SumPow = this.GetSumFromList(item.SumList, Block.BlockNum); if (POW.SumHash === undefined || SumPow > POW.SumPow) { POW.SumPow = SumPow POW.SumHash = item.SumHash POW.SumList = item.SumList global.AddInfoBlock(Block, "SumPow:" + POW.SumPow) Block.CheckMaxSum = false } return SumPow; } return 0; } GetMaxSumList() { var Arr = []; var start, finish; start = this.CurrentBlockNum + global.TIME_START_LOAD - 2 finish = this.CurrentBlockNum for (var b = start; b <= finish; b++) { var Block = this.GetBlock(b); if (Block && Block.bSave && Block.MaxSum && Block.MaxSum.SumHash) { var POW = Block.MaxSum; var item = { BlockNum: Block.BlockNum, SumHash: POW.SumHash, SumList: POW.SumList, }; Arr.push(item) } } return Arr; } ToMaxSumList(Arr) { var start, finish; start = this.CurrentBlockNum + global.TIME_START_LOAD - 2 finish = this.CurrentBlockNum for (var i = 0; i < Arr.length; i++) { var item = Arr[i]; if (item && item.BlockNum >= start && item.BlockNum <= finish) { var Block = this.GetBlock(item.BlockNum); if (Block) { this.AddToMaxSum(Block, item) this.CheckMaxSum(Block) } } } } GetBlockList(CurBlockNum) { var arr = []; for (var b = CurBlockNum - global.SUM_LIST_LENGTH + 1; b <= CurBlockNum; b++) { var Block = this.GetBlock(b); if (Block && Block.bSave) { var item = { AddrHash: Block.AddrHash, SeqHash: Block.SeqHash, }; arr.push(item) } else { return []; } } return arr; } GetSumFromList(arr, CurBlockNum) { var SumPow = 0; if (arr.length !== global.SUM_LIST_LENGTH) return SumPow; var CountLoad = 0; var BlockNumStart = CurBlockNum - arr.length + 1; for (var i = 0; i < arr.length; i++) { var Item = arr[i]; if (Item) { Item.BlockNum = BlockNumStart + i var Value = global.GetHashFromSeqAddr(Item.SeqHash, Item.AddrHash, Item.BlockNum, undefined, global.MINING_VERSION_NUM); SumPow += global.GetPowPower(Value.PowHash) Item.Hash3 = Value.Hash } else { break; } } return SumPow; } GetArrayFromTxTree(Block) { if (!Block.PowTxTree) return []; var BufLength = 0; var arr = []; var it = Block.PowTxTree.iterator(), Item; while ((Item = it.next()) !== null) { arr.push(Item) BufLength += Item.body.length if (BufLength > global.MAX_BLOCK_SIZE) break; } return arr; } GetArrayFromTicketTree(Block) { if (!Block.PowTicketTree) return []; var arr = []; var it = Block.PowTicketTree.iterator(), Item; while ((Item = it.next()) !== null) { arr.push(Item) } return arr; } CheckPrioritetTx(Tr) { if (Tr.Prioritet === undefined) { var Body = Tr.body; Tr.Prioritet = global.MAX_LENGTH_SENDER_MAP var App = global.DAppByType[Body[0]]; if (App) { Tr.SenderNum = App.GetSenderNum(Tr.num, Body) if (Tr.SenderNum && Tr.SenderNum > 0) { Tr.Prioritet = this.GetSenderPrioritet(Tr.num, Tr.SenderNum) Tr.TimePow = Tr.Prioritet + Tr.power } } } } GetSenderPrioritet(BlockNum, SenderNum) { //defiend in transaction-validator.ts(CSmartContract) } AddToQuote(Tree, Tr) { this.CheckPrioritetTx(Tr) var Tr0 = Tree.find(Tr); if (Tr0) { return 3; } else { Tree.insert(Tr) if (Tree.size > global.MAX_TRANSACTION_LIMIT) { var maxitem = Tree.max(); Tree.remove(maxitem) if (global.CompareArr(maxitem.HashPow, Tr.HashPow) === 0) return 0; } return 1; } } IsValidTicket(Tr, BlockNum): any { // defiend in transaction-validator.ts(CSmartContract) } IsValidTransaction(Tr, BlockNum): any { // defiend in transaction-validator.ts(CSmartContract) } AddDAppTransactions(BlockNum, Arr) { // defiend in transaction-validator.ts(CSmartContract) } AddTicketToBlockQuote(Block, Tr) { if (Block.PowTicketTree) { var Res = this.IsValidTicket(Tr, Block.BlockNum); if (Res >= 1) { Res = this.AddToQuote(Block.PowTicketTree, Tr) if (Res) return Block.PowTicketTree.find(Tr); } return null; } } AddTrToBlockQuote(Block, Tr, bTTAdd?) { if (Block.PowTxTree) { var Res = this.IsValidTransaction(Tr, Block.BlockNum); if (Res >= 1) { if (bTTAdd) { Res = this.AddToQuote(Block.PowTicketTree, Tr) if (Res <= 0) return Res; } Res = this.AddToQuote(Block.PowTxTree, Tr) } return Res; } } GetBlockContext(BlockNum) { if (BlockNum === undefined || !this.IsCorrectBlockNum(BlockNum)) return undefined; var Context = this.GetBlock(BlockNum); if (!Context || !Context.StartTimeNum) { Context = this.CreateBlockContext() Context.BlockNum = BlockNum Context.DELTA_CURRENT_TIME = global.GetDeltaCurrentTime() Context.StartTimeNum = (BlockNum - 1 + global.BLOCK_DELTA_ACTIVATE) * global.CONSENSUS_PERIOD_TIME + global.START_NETWORK_DATE this.BlockChain[BlockNum] = Context } if (!Context.TransferFromAddr) { Context.TransferFromAddr = {} Context.LevelsTransfer = [] } return Context; } StartBlock(Block) { Block.Active = true } IsCorrectBlockNum(BlockNum) { var start = this.CurrentBlockNum - global.BLOCK_PROCESSING_LENGTH; var finish = this.GetLastCorrectBlockNum(); if (BlockNum < start || BlockNum > finish) { return false; } return true; } GetLastCorrectBlockNum() { return this.CurrentBlockNum + 4; } GetStrSendCount(Block) { if (!Block) return ""; var Str = ""; var Count = 0; for (var L = 0; L < Block.LevelsTransfer.length; L++) { var Transfer = Block.LevelsTransfer[L]; Str = Str + "," + Transfer.SendCount if (typeof Transfer.SendCount === "number") Count = Count + Transfer.SendCount } return "" + Count + ":[" + Str.substr(1) + "]"; } GetStrGetCount(Block) { if (!Block) return ""; var Str = ""; var Count = 0; for (var L = 0; L < Block.LevelsTransfer.length; L++) { var Transfer = Block.LevelsTransfer[L]; Str = Str + "," + Transfer.GetCount Count = Count + Transfer.GetCount } return "" + Count + ":[" + Str.substr(1) + "]"; } ToStrBlocks(DopStr) { var num = Math.floor(this.CurrentBlockNum / 3) * 3; var start = num - global.BLOCK_PROCESSING_LENGTH2 + 2; var finish = this.CurrentBlockNum; if (!DopStr) DopStr = "" var Str = ""; for (var b = start; b <= finish; b++) { var hashStr = ""; var Block = this.GetBlock(b); if (Block && Block.ErrRun) { if (Block.ErrRun) hashStr = Block.ErrRun.substr(0, 5) else if (Block && Block.TreeHash) hashStr = "-" + global.GetHexFromAddres(Block.TreeHash).substr(0, 3) + "-" } else if (Block && Block.TreeHash) { hashStr = global.GetHexFromAddres(Block.TreeHash).substr(0, 5) } Str = Str + "|" + (hashStr + " ").substr(0, 5) } Str = Str.substr(1) global.ToInfo("" + finish + " -> " + Str + " " + DopStr) } PreparePOWHash(Block) { if (!Block.TreeHash) Block.TreeHash = [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 PrevHash = this.GetPrevHash(Block); if (!PrevHash) { global.AddInfoBlock(Block, "-err prev hash-") return false; } Block.PrevHash = PrevHash Block.SeqHash = this.GetSeqHash(Block.BlockNum, Block.PrevHash, Block.TreeHash) this.CreatePOWNew(Block) Block.Prepared = true if (global.USE_MINING && !Block.StartMining) { Block.StartMining = true global.AddInfoBlock(Block, "-send mining-") global.SetCalcPOW(Block, "FastCalcBlock") } return true; } CalcTreeHashFromArrTr(BlockNum, arrTr) { var arrHASH = []; for (var i = 0; i < arrTr.length; i++) { var Tr = arrTr[i]; arrHASH.push(Tr.HASH) } var Tree = global.CalcMerklFromArray(BlockNum, arrHASH); return Tree.Root; } CreateTreeHash(Block) { if (Block.EndExchange) return; Block.EndExchange = true if (Block.bSave) return; var PrevBlock = this.GetBlock(Block.BlockNum - 1); if (PrevBlock && !PrevBlock.EndExchange && !PrevBlock.bSave) { global.AddInfoBlock(Block, "Prev Not End Exchange") return; } global.AddInfoBlock(Block, "End Exchange,N=" + Block.TransferNodesCount) var arrContent = []; var arrHASH = []; var arrTr = this.GetArrayFromTxTree(Block); this.AddDAppTransactions(Block.BlockNum, arrTr) for (var i = 0; i < arrTr.length; i++) { var Tr = arrTr[i]; arrContent.push(Tr.body) arrHASH.push(Tr.HASH) } var Tree = global.CalcMerklFromArray(Block.BlockNum, arrHASH); Block.TreeHash = Tree.Root Block.arrContent = arrContent Block.TrCount = Block.arrContent.length } WatchdogSaved(BlockNum) { var Block = this.GetBlock(BlockNum); if (!Block) { global.ToLog("#1 WatchdogSaved: no BlockNum=" + BlockNum) return; } if (Block.bSave) { var BlockDB = this.ReadBlockDB(BlockNum); if (!BlockDB) { Block.bSave = false return; } if (global.CompareArr(BlockDB.Hash, Block.Hash) !== 0) { global.AddInfoBlock(Block, "=ERR:WATCHDOG=") global.ToLog("#3 WatchdogSaved: Error Hash on Num=" + BlockNum) return; } if (global.CompareArr(BlockDB.SumHash, Block.SumHash) !== 0) { global.AddInfoBlock(Block, "=ERR:WATCHDOG=") global.ToLog("#4 WatchdogSaved: Error SumHash on Num=" + BlockNum) return; } if (global.CompareArr(BlockDB.SeqHash, Block.SeqHash) !== 0) { global.AddInfoBlock(Block, "=ERR:WATCHDOG=") global.ToLog("#5 WatchdogSaved: Error SeqHash on Num=" + BlockNum) return; } var PrevHash = this.GetPrevHash(Block); if (!PrevHash) { global.AddInfoBlock(Block, "=ERR:WATCHDOG=") global.ToLog("#6 WatchdogSaved: Error PrevHash on Num=" + BlockNum) return; } var SeqHash = this.GetSeqHash(Block.BlockNum, PrevHash, Block.TreeHash); if (global.CompareArr(SeqHash, Block.SeqHash) !== 0) { global.AddInfoBlock(Block, "=ERR:WATCHDOG=") global.ToLog("#7 WatchdogSaved: Error SeqHash on Num=" + BlockNum) return; } PrevHash = this.GetPrevHashDB(BlockDB) SeqHash = this.GetSeqHash(BlockDB.BlockNum, PrevHash, BlockDB.TreeHash) if (global.CompareArr(SeqHash, BlockDB.SeqHash) !== 0) { global.AddInfoBlock(Block, "=ERR:WATCHDOG=") global.ToLog("#8 WatchdogSaved: Error SeqHash on Num=" + BlockNum) return; } } } DoBlockChain() { if (global.glStopNode) return; if (!global.CAN_START) return; this.StartConsensus() var CURRENTBLOCKNUM = this.CurrentBlockNum; if (global.GrayConnect()) { if (!this.LoadHistoryMode) this.StartSyncBlockchain(undefined, 1) return; } if (this.LoadHistoryMode) return; var bWasSave = false; var LoadBlockNum; var LoadHash; var start_save = CURRENTBLOCKNUM + global.TIME_START_SAVE; for (var BlockNum = CURRENTBLOCKNUM - global.BLOCK_PROCESSING_LENGTH2; BlockNum > global.BLOCK_PROCESSING_LENGTH2 && BlockNum < CURRENTBLOCKNUM; BlockNum++) { var Block = this.GetBlock(BlockNum); if (!Block) { Block = this.GetBlockContext(BlockNum) if (!Block) { continue; } } if (Block.bSave) { var BlockDB = this.ReadBlockDB(BlockNum); if (!BlockDB) { Block.bSave = false } } if (global.WATCHDOG_DEV) this.WatchdogSaved(Block.BlockNum) if (Block.bSave) { bWasSave = true if (Block.MaxSum && !Block.CheckMaxSum) { global.AddInfoBlock(Block, "CheckMaxSum") this.CheckMaxSum(Block) } if (BlockNum <= CURRENTBLOCKNUM - global.BLOCK_PROCESSING_LENGTH * 4) { Block.TransferFromAddr = undefined Block.LevelsTransfer = undefined Block.mapData = undefined Block.MaxPOW = undefined Block.MaxSum = undefined Block.arrContent = undefined if (Block.PowTxTree) { Block.PowTxTree.clear() Block.PowTxTree = undefined } } continue; } var PrevBlock = this.GetBlock(BlockNum - 1); if (!PrevBlock) { Block.HasErr = 1 global.AddInfoBlock(Block, "!PrevBlock") continue; } if (BlockNum >= CURRENTBLOCKNUM + global.TIME_END_EXCHANGE) { if (!Block.Active) { global.AddInfoBlock(Block, "WAIT ACTIVATE") continue; } else if (!Block.EndExchange) { global.AddInfoBlock(Block, "WAIT EXCHANGE") continue; } } if (BlockNum === CURRENTBLOCKNUM + global.TIME_START_POW || Block.EndExchange) if (!Block.Prepared) { if (!Block.EndExchange) this.CreateTreeHash(Block) global.AddInfoBlock(Block, "Start POW") this.PreparePOWHash(Block) if (!Block.Prepared) global.AddInfoBlock(Block, "!!Prepared") continue; } if (!Block.EndExchange) { global.AddInfoBlock(Block, "Not EndExchange") Block.HasErr = 1 Block.Prepared = 0 this.CreateTreeHash(Block) } if (!Block.Prepared) { Block.HasErr = 1 global.AddInfoBlock(Block, "Not was Prepared") this.PreparePOWHash(Block) if (!Block.Prepared) continue; } { var PrevHash = this.GetPrevHash(Block); if (!PrevHash) { Block.HasErr = 1 continue; } var SeqHash = this.GetSeqHash(Block.BlockNum, PrevHash, Block.TreeHash); if (global.CompareArr(SeqHash, Block.SeqHash) !== 0) { Block.HasErr = 1 global.AddInfoBlock(Block, "New fast pow") this.PreparePOWHash(Block) } if (Block.MaxPOW && Block.MaxPOW.SeqHash && Block.MaxPOW.AddrHash && Block.MaxPOW.LocalSeqHash && global.CompareArr(Block.SeqHash, Block.MaxPOW.LocalSeqHash) === 0) { if (global.CompareArr(Block.SeqHash, Block.MaxPOW.LocalSeqHash) === 0 && global.CompareArr(Block.MaxPOW.PowLocalHash, Block.PowHash) < 0) { Block.AddrHash = Block.MaxPOW.LocalAddrHash global.CalcHashBlockFromSeqAddr(Block, Block.PrevHash, global.MINING_VERSION_NUM) global.AddInfoBlock(Block, "->Local lider:" + global.GetPowPower(Block.PowHash)) } if (global.CompareArr(Block.SeqHash, Block.MaxPOW.SeqHash) === 0 && global.CompareArr(Block.MaxPOW.AddrHash, Block.AddrHash) !== 0 && global.CompareArr(Block.MaxPOW.PowHash, Block.PowHash) < 0) { Block.AddrHash = Block.MaxPOW.AddrHash global.CalcHashBlockFromSeqAddr(Block, Block.PrevHash, global.MINING_VERSION_NUM) global.AddInfoBlock(Block, "->Max lider") } } else { Block.HasErr = 1 global.AddInfoBlock(Block, "ERROR MaxPOW") } if (Block.MaxPOW && Block.MaxPOW.SeqHash && !Block.CheckMaxPow && !Block.CheckMaxSum && global.CompareArr(Block.SeqHash, Block.MaxPOW.SeqHash) !== 0) { global.AddInfoBlock(Block, "CheckMaxPow") this.CheckingMaxPowOther(Block) } if (BlockNum > start_save) continue; if (PrevBlock.bSave && this.BlockNumDB + 1 >= Block.BlockNum) { this.AddToStatBlockConfirmation(Block) var Power = global.GetPowPower(Block.PowHash); if (this.WriteBlockDB(Block)) { if (Block.arrContent && Block.arrContent.length) global.ADD_TO_STAT("MAX:TRANSACTION_COUNT", Block.arrContent.length) global.AddInfoBlock(Block, "SAVE:" + Power + " TH:" + this.GetStrFromHashShort(Block.TreeHash).substr(0, 4)) } else { Block.HasErr = 1 global.AddInfoBlock(Block, "ERROR WRITE DB") } this.AddToMaxSum(Block, { SumHash: Block.SumHash, SumList: this.GetBlockList(Block.BlockNum), }) if (typeof global.RESYNC_CONDITION === "object") { if (!this.OwnBlockCount) this.OwnBlockCount = 0 var Miner = global.ReadUintFromArr(Block.AddrHash, 0); var MultK = global.RESYNC_CONDITION.K_POW; var MaxBlocks = global.RESYNC_CONDITION.OWN_BLOCKS; if (Miner === global.GENERATE_BLOCK_ACCOUNT) { this.OwnBlockCount++ if (this.OwnBlockCount >= MaxBlocks) { var PrevSumPow = this.GetAvgPowBlock(Block.BlockNum - 2 * MaxBlocks, MaxBlocks); var CurrentPow = this.GetAvgPowBlock(Block.BlockNum - MaxBlocks, MaxBlocks); if (CurrentPow === 0 || PrevSumPow - CurrentPow >= MultK) { global.ToLog("START RESYNC CONDITION") this.OwnBlockCount = 0 this.StartSyncBlockchain() return; } } } else { this.OwnBlockCount = 0 } } } else { Block.HasErr = 1 if (!PrevBlock.bSave) global.AddInfoBlock(Block, "Prev block not saved") else global.AddInfoBlock(Block, "Low BlockNumDB") } } } var MaxNumBlockDB = this.GetMaxNumBlockDB(); if (CURRENTBLOCKNUM + global.BLOCK_PROCESSING_LENGTH2 > MaxNumBlockDB && CURRENTBLOCKNUM - global.BLOCK_PROCESSING_LENGTH2 < MaxNumBlockDB) for (var BlockNum = CURRENTBLOCKNUM - global.BLOCK_PROCESSING_LENGTH2; BlockNum > global.BLOCK_PROCESSING_LENGTH2 && BlockNum < start_save; BlockNum++) { var Block = this.GetBlock(BlockNum); if (Block && !Block.bSave && Block.TrCount && Block.TreeHash && !global.IsZeroArr(Block.TreeHash) && !Block.WasSaveDataTree) { this.PreSaveDataTreeToDB(Block) Block.WasSaveDataTree = 1 global.AddInfoBlock(Block, "*PRESAVE DATA TREE*") global.ToLog("PRESAVE DATA: " + Block.BlockNum, 2) } } this.RelayMode = !bWasSave this.FREE_MEM_BLOCKS(CURRENTBLOCKNUM - global.BLOCK_COUNT_IN_MEMORY) } GetAvgPowBlock(StartNum, CountNum) { var Count = 0; var SumPow = 0; for (var Num = StartNum; Num < StartNum + CountNum; Num++) { var Block = this.GetBlock(Num); if (Block && Block.bSave) { var Power = global.GetPowPower(Block.PowHash); SumPow += Power Count++ } } if (!Count) return 0; else return SumPow / Count; } CreatePOWNew(Block) { global.CreateHashMinimal(Block, global.GENERATE_BLOCK_ACCOUNT) this.AddToMaxPOW(Block, { SeqHash: Block.SeqHash, AddrHash: Block.AddrHash, PrevHash: Block.PrevHash, TreeHash: Block.TreeHash, }) } SetNoPOW(BlockNumFrom, bReload, RefBlockNum) { var CurNum = BlockNumFrom; var finish = this.GetLastCorrectBlockNum(); while (true) { var BlockMem = this.BlockChain[CurNum]; if (BlockMem) { if (BlockMem.Prepared) { global.AddInfoBlock(BlockMem, "-reset POW:" + RefBlockNum + "/" + bReload) BlockMem.bSave = false BlockMem.Prepared = false BlockMem.StartMining = false this.PreparePOWHash(BlockMem) } this.RecreateMaxPOW(BlockMem) } if (!BlockMem && CurNum > finish) break; CurNum++ } } MiningProcess(msg) { var BlockMining = this.GetBlock(msg.BlockNum); if (!BlockMining) { teraManager.SendToWebClient({ msg: msg, error: '!BlockMining' }) return; } if (!BlockMining.StartMining || BlockMining.bSave) { teraManager.SendToWebClient({ msg: msg, error: `!BlockMining.StartMining ${BlockMining.StartMining} || BlockMining.bSave ${BlockMining.bSave}` }) return; } if (BlockMining && BlockMining.Hash && BlockMining.SeqHash && global.CompareArr(BlockMining.SeqHash, msg.SeqHash) === 0) { var ValueOld = global.GetHashFromSeqAddr(BlockMining.SeqHash, BlockMining.AddrHash, BlockMining.BlockNum); var ValueMsg = global.GetHashFromSeqAddr(msg.SeqHash, msg.AddrHash, BlockMining.BlockNum); var bWas = 0; if (global.CompareArr(ValueOld.Hash1, ValueMsg.Hash1) > 0) { var Nonce1 = global.ReadUintFromArr(msg.AddrHash, 12); var DeltaNum1 = global.ReadUint16FromArr(msg.AddrHash, 24); global.WriteUintToArrOnPos(BlockMining.AddrHash, Nonce1, 12) global.WriteUint16ToArrOnPos(BlockMining.AddrHash, DeltaNum1, 24) bWas += 1 } if (global.CompareArr(ValueOld.Hash2, ValueMsg.Hash2) > 0) { var Nonce0 = global.ReadUintFromArr(msg.AddrHash, 6); var Nonce2 = global.ReadUintFromArr(msg.AddrHash, 18); var DeltaNum2 = global.ReadUint16FromArr(msg.AddrHash, 26); global.WriteUintToArrOnPos(BlockMining.AddrHash, Nonce0, 6) global.WriteUintToArrOnPos(BlockMining.AddrHash, Nonce2, 18) global.WriteUint16ToArrOnPos(BlockMining.AddrHash, DeltaNum2, 26) bWas += 2 } if (!bWas) return; var ValueNew = global.GetHashFromSeqAddr(BlockMining.SeqHash, BlockMining.AddrHash, BlockMining.BlockNum); BlockMining.Hash = ValueNew.Hash BlockMining.PowHash = ValueNew.PowHash BlockMining.Power = global.GetPowPower(BlockMining.PowHash) global.ADD_TO_STAT("MAX:POWER", BlockMining.Power) var Power = global.GetPowPower(BlockMining.PowHash); var HashCount = Math.pow(2, Power); global.ADD_HASH_RATE(HashCount) global.AddInfoBlock(BlockMining, "Set POW: " + Power) this.SetNoPOW(BlockMining.BlockNum + 8, 0, BlockMining.BlockNum) this.AddToMaxPOW(BlockMining, { SeqHash: BlockMining.SeqHash, AddrHash: BlockMining.AddrHash, PrevHash: BlockMining.PrevHash, TreeHash: BlockMining.TreeHash, }) if (bWas == 3) { setTimeout(() => { let webmsg: any = { BlockNum: msg.BlockNum } webmsg.Mining = { SeqHash: global.GetHexFromArr(BlockMining.SeqHash), AddrHash: global.GetHexFromArr(BlockMining.AddrHash), PrevHash: global.GetHexFromArr(BlockMining.PrevHash), TreeHash: global.GetHexFromArr(BlockMining.TreeHash), Hash: global.GetHexFromArr(BlockMining.Hash), PowHash: global.GetHexFromArr(BlockMining.PowHash) } Object.assign(webmsg, { HashCount, Power, Num: msg.NodeNum }) teraManager.SendToWebClient(webmsg) }, 1) } } } }; global.TreeBlockBuf = new STreeBuffer(50 * 1000, global.CompareItemHashSimple, "string"); var PrevTimeIdle = 0; OnTimeIdle(); function OnTimeIdle() { var CurTime = Date.now(); var Delta = CurTime - PrevTimeIdle; if (Delta <= 51) { global.ADD_TO_STAT("TIME_IDLE", 5); } setTimeout(OnTimeIdle, 49); PrevTimeIdle = CurTime; };