tera/src/core/block-loader.ts

1364 lines
54 KiB
TypeScript

/*
* @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 * as fs from 'fs'
import CRest from './rest-loader'
import { TYPE_TRANSACTION } from '../constant/account';
import { STreeBuffer } from './base';
import { RBTree } from './library';
import { DB_FORMAT } from '../constant/db-format';
import * as crypto from 'crypto';
import CNode from './node';
import { LoadContext, TeraBlock, ContextTask, TeraChain, SocketSendInfo } from '../interfaces/server';
import './block-loader-const'
const STAT_BLOCK_LOAD_PERIOD = global.CONSENSUS_PERIOD_TIME / 5;
export default class CBlock extends CRest {
MapMapLoaded: {}
BlockChain: { [x: string]: any; }
ChainID: number
BlockID: number
TaskNodeIndex: number
LoadedChainList: any[]
LastChainLoad: any
StartLoadBlockTime: number
LoadHistoryMode: boolean
MapBlockBodyLoad: { [x: string]: any; }
BlockNumDB: number
RelayMode: boolean
LoadHistoryMessage: boolean
LastLoadedBlockNum: number
LoadHistoryContext: LoadContext
LoadBlockStatNum: number
BADHashCount: number
ActualNodes: RBTree<CNode>
constructor(SetKeyPair: crypto.ECDH, RunIP: string, RunPort: number, UseRNDHeader: boolean, bVirtual: boolean) {
super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual)
this.MapMapLoaded = {}
this.BlockChain = {}
this.ChainID = 0
this.BlockID = 0
this.TaskNodeIndex = 0
this.LoadedChainList = []
this.LastChainLoad = undefined
this.StartLoadBlockTime = 0
this.LoadHistoryMode = false
this.MapBlockBodyLoad = {}
if (!global.ADDRLIST_MODE && !this.VirtualMode) {
let Self = this;
setTimeout(function() {
Self.CheckStartedBlocks()
setInterval(Self.LoopChainLoad.bind(Self), 100)
setInterval(Self.LoopBlockLoad.bind(Self), 10)
setInterval(Self.LoopBlockBodyLoad.bind(Self), 1 * 1000)
}, 1000)
}
}
StopNode() {
global.glStopNode = true
}
GenesisBlockHeaderDB(Num: number) {
if (Num < 0)
return undefined;
var Block: any = {
BlockNum: Num,
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],
AddrHash: global.DEVELOP_PUB_KEY0,
Hash: this.GetHashGenesis(Num),
PowHash: this.GetHashGenesis(Num),
PrevHash: [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],
SeqHash: [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],
SumHash: [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],
Comment1: "GENESIS",
Comment2: "",
TrCount: 0,
TrDataPos: 0,
TrDataLen: 0,
};
Block.SeqHash = this.GetSeqHash(Block.BlockNum, Block.PrevHash, Block.TreeHash)
Block.SumPow = 0
Block.bSave = true
return Block;
}
CheckStartedBlocks() {
this.FindStartBlockNum()
if (this.UseTruncateBlockDB)
this.TruncateBlockDB(this.UseTruncateBlockDB)
var CurNum = global.GetCurrentBlockNumByTime();
if (CurNum <= this.BlockNumDB) {
this.TruncateBlockDB(CurNum)
}
CurNum = this.GetMaxNumBlockDB()
if (CurNum <= this.BlockNumDB) {
this.TruncateBlockDB(CurNum)
this.BlockNumDB = CurNum
}
if (this.BlockNumDB < global.BLOCK_PROCESSING_LENGTH2)
this.CreateGenesisBlocks()
if (fs.existsSync(global.GetCodePath("EXPERIMENTAL/_run.js"))) {
require(global.GetCodePath("EXPERIMENTAL/_run.js")).Run()
}
this.LoadMemBlocksOnStart()
}
CreateGenesisBlocks() {
global.ToLog("====CreateGenesisBlock====")
var PrevArr = [];
for (var n = 0; n < global.BLOCK_PROCESSING_LENGTH2; n++) {
var Block = this.GenesisBlockHeaderDB(n);
PrevArr[n] = Block
this.WriteBlockDB(Block)
}
return PrevArr;
}
GetPrevHash(Block: TeraBlock) {
var startPrev = Block.BlockNum - global.BLOCK_PROCESSING_LENGTH2;
var Sum = 0;
var arr = [];
for (var i = 0; i < global.BLOCK_PROCESSING_LENGTH; i++) {
var PrevBlock = this.GetBlock(startPrev + i);
if (PrevBlock && PrevBlock.bSave) {
Sum = Sum + PrevBlock.SumPow
arr.push(PrevBlock.Hash)
}
else {
return undefined;
}
}
var PrevHash = global.CalcHashFromArray(arr, true);
return PrevHash;
}
GetPrevHashDB(Block: TeraBlock) {
var startPrev = Block.BlockNum - global.BLOCK_PROCESSING_LENGTH2;
var arr = [];
for (var i = 0; i < global.BLOCK_PROCESSING_LENGTH; i++) {
var num = startPrev + i;
var PrevBlock = this.ReadBlockHeaderDB(num);
if (!PrevBlock || !PrevBlock.bSave) {
global.ToError(" ERROR CALC BLOCK: " + Block.BlockNum + " - prev block not found: " + num)
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];
}
arr.push(PrevBlock.Hash)
}
var PrevHash = global.CalcHashFromArray(arr, true);
return PrevHash;
}
StartSyncBlockchain(Node?: CNode, bSilent?: boolean, bCheckPoint?: boolean, PrevStartedBlockNum?: number) {
this.FREE_ALL_MEM_CHAINS()
if (global.NO_HISTORY_MODE) {
this.LoadHistoryMode = false
return;
}
if (global.CREATE_ON_START && !global.LOCAL_RUN)
return;
if (!global.GrayConnect())
this.RelayMode = true
else
this.RelayMode = false
if (!bSilent)
this.RelayMode = true
var StartBlockNum;
if (PrevStartedBlockNum) {
var DeltaNum = Math.floor(1.2 * (this.BlockNumDB - PrevStartedBlockNum));
if (DeltaNum < 1000)
DeltaNum = 1000
StartBlockNum = this.BlockNumDB - DeltaNum
if (StartBlockNum <= 0)
StartBlockNum = 15
global.ToLog("Current DeltaNum=" + DeltaNum + " StartBlockNum=" + StartBlockNum, 2)
} else {
StartBlockNum = this.BlockNumDB
}
this.LoadHistoryMode = true
this.LoadHistoryMessage = !bSilent
this.LoadHistoryContext = {
PrevBlockNum: - 1,
Node: Node,
BlockNum: this.BlockNumDB,
MapSend: {},
Foward: 1,
Pause: 0,
DeltaBlockNum: 10,
StartTimeHistory: Date.now(),
MaxTimeOut: 30 * 1000
}
if (!bSilent && !bCheckPoint && global.REST_START_COUNT) {
this.CheckSyncRest()
}
if (!this.ActualNodes.size) {
global.ToLog("There is no connections to other nodes")
}
else {
if (this.LoadHistoryMessage) {
global.ToLog("Start synchronization")
}
}
}
LoopSyncBlockchain() {
if (!this.ActualNodes.size)
return;
var Context;
if (this.LoadRestContext && this.LoadRestContext.Mode < 200)
Context = this.LoadRestContext
else
Context = this.LoadHistoryContext
if (Context.PrevBlockNum === Context.BlockNum) {
var DeltaTime = Date.now() - Context.StartTimeHistory;
if (DeltaTime > Context.MaxTimeOut) {
global.ToLog("DETECT TIMEOUT LOAD")
this.StartSyncBlockchain(undefined, undefined, undefined, Context.BlockNum)
return;
}
}
else {
Context.PrevBlockNum = Context.BlockNum
Context.StartTimeHistory = Date.now()
}
if (Context.LoopSyncRest) {
this.LoopSyncRest()
return;
}
if (Context.Pause) {
if (this.LoadedChainList.length) {
return;
}
Context.Pause = 0
Context.BlockNum = this.BlockNumDB
}
var BlockDB = this.ReadBlockHeaderDB(Context.BlockNum);
if (!BlockDB || this.BlockNumDB >= global.GetCurrentBlockNumByTime() - global.BLOCK_PROCESSING_LENGTH - 2) {
this.LoadHistoryMode = false
if (this.LoadHistoryMessage)
global.ToLog("Finish synchronization")
if (!BlockDB)
return;
}
var Ret = this.GetNextNode(Context, Context.BlockNum, 1);
if (Ret.Result) {
var Node = Ret.Node;
this.SendF(Node, { "Method": "GETBLOCKHEADER", "Context": Context, "Data": { Foward: 1, BlockNum: Context.BlockNum, Hash: BlockDB.SumHash } })
}
}
StartLoadBlockHeader(LoadHash: Buffer, Num: number, StrInfo: string, bIsSum: boolean) {
if (this.LoadHistoryMode)
return;
if (global.NO_HISTORY_MODE)
return;
this.StartLoadBlockTime = Date.now()
if (Num > this.CurrentBlockNum + global.TIME_START_SAVE) {
return;
}
bIsSum = bIsSum || false
var Tree = this.GetHistoryTree("StartLoadBlockHeader");
if (Tree.find({ hash: LoadHash }))
return false;
Tree.insert({ hash: LoadHash })
var chain: any = {
id: 0,
Count: 16,
BlockNum: Num,
IsSum: bIsSum,
Hash: LoadHash,
time: undefined,
FindBlockDB: false,
LoadDB: false,
LoadCountDB: 0,
LoadSumDB: 0,
LoadSum: 0,
ParentChain: undefined,
RootChain: undefined,
BlockNumStart: Num,
HashStart: LoadHash,
IsSumStart: bIsSum,
BlockHead: undefined,
MapSend: {},
Comment2: "",
StopSend: false,
Info: "",
Error: false,
};
this.ChainBindMethods(chain)
chain.AddInfo(StrInfo)
this.SetChainNum(chain)
var max = 3;
while (max > 0) {
max--
if (!this.SendChainNext(chain, false))
break;
}
return true;
}
SetChainNum(chain) {
if (!chain.id) {
this.ChainID++
chain.id = this.ChainID
}
this.LoadedChainList.push(chain)
}
LoopChainLoad() {
if (global.glStopNode)
return;
if (this.UseTruncateBlockDB)
this.TruncateBlockDB(this.UseTruncateBlockDB)
if (this.LoadHistoryMode) {
this.LoopSyncBlockchain()
return;
}
if (this.BlockNumDB < this.CurrentBlockNum - global.BLOCK_PROCESSING_LENGTH2) {
this.StartSyncBlockchain()
return;
}
if (global.LOAD_TO_BEGIN && this.BlockNumDBMin) {
this.SendLoadToBegin()
}
var CountStopSend = 0;
var min_num = this.CurrentBlockNum - global.MAX_COUNT_CHAIN_LOAD;
var min_num_load = this.CurrentBlockNum;
for (var i = 0; i < this.LoadedChainList.length; i++) {
var chain = this.LoadedChainList[i];
if (!chain) {
this.LoadedChainList.splice(i, 1)
continue;
}
var RootChain = chain.GetRootChain();
if (chain.RootChain)
chain.RootChain = RootChain
if (RootChain.BlockNum < min_num_load)
min_num_load = RootChain.BlockNum
if (!chain.StopSend) {
if (chain.BlockHead) {
if (chain.BlockNum < this.CurrentBlockNum - global.COUNT_HISTORY_BLOCKS_FOR_LOAD) {
if (global.WATCHDOG_DEV)
global.ToLog("Very long length of blocks to load history, stop chain with id=" + chain.id + " (" + chain.BlockNum + "-" + chain.BlockNumMax + ")")
chain.StopSend = true
chain.AddInfo("Stop load #1")
this.FREE_ALL_MEM_CHAINS()
return;
}
else
if (chain.BlockNumMax < min_num) {
if (global.WATCHDOG_DEV)
global.ToLog("Timeout - stop load chain with id=" + chain.id + " (" + chain.BlockNum + "-" + chain.BlockNumMax + ")")
chain.StopSend = true
chain.AddInfo("Stop load #2")
this.ClearChains(chain, false)
}
}
}
if (chain && !chain.IsSum && !chain.StopSend) {
var StrKey = "H:" + global.GetHexFromArr(chain.Hash);
var Map = this.GetMapLoadedFromChain(chain);
var WasBlock = Map[StrKey];
if (WasBlock && WasBlock.chain !== chain && global.CompareArr(WasBlock.Hash, chain.Hash) === 0 && !WasBlock.chain.Deleted) {
if (global.WATCHDOG_DEV)
global.ToLog("Was hash in chain " + WasBlock.chain.id + " - stop load chain with id=" + chain.id + " (" + chain.BlockNum + ")")
chain.Comment2 = "was hash"
chain.StopSend = true
}
}
if (chain && chain.StopSend) {
CountStopSend++
}
chain = this.LoadedChainList[i]
if (chain && !chain.GetFindDB() && !chain.StopSend) {
this.SendChainNext(chain, true)
}
}
global.ADD_TO_STAT("MAX:LOADEDCHAINLIST", this.LoadedChainList.length)
this.FREE_MEM_CHAINS(min_num_load)
this.LastLoadedBlockNum = 0
if (this.LoadedChainList.length > global.COUNT_HISTORY_BLOCKS_FOR_LOAD) {
if (global.WATCHDOG_DEV)
global.ToLog("LoadedChainList>COUNT_HISTORY_BLOCKS_FOR_LOAD -> FREE_ALL_MEM_CHAINS")
this.FREE_ALL_MEM_CHAINS()
}
}
GetNextNode(task: ContextTask, keyid?: string | number, checktime?: number | boolean, BlockNum?: number) {
var CurTime = global.GetCurrentTime(0) - 0;
if (checktime && task.time) {
var Delta = CurTime - task.time;
if (Delta < global.PACKET_ALIVE_PERIOD_NEXT_NODE)
return { Result: false, timewait: true };
}
task.time = undefined
var StartI = 0;
if (task.Node)
StartI = - 1
var timewait = false;
var arr = this.GetActualNodes();
arr.sort(function(a, b) {
return b.BlockProcessCount - a.BlockProcessCount;
})
if (arr.length > 40)
arr.length = 40
for (var i = StartI; i < arr.length; i++) {
var Node;
if (i === - 1) {
Node = task.Node
task.Node = undefined
}
else {
this.TaskNodeIndex++
Node = arr[this.TaskNodeIndex % arr.length]
}
if (Node.Active) {
if (!Node.INFO || !Node.INFO.WasPing || Node.StopGetBlock || (Node.INFO.CheckPointHashDB && global.CHECK_POINT.BlockNum && global.CompareArr(global.CHECK_POINT.Hash,
Node.INFO.CheckPointHashDB) !== 0)) {
timewait = true
continue;
}
if (BlockNum !== undefined && Node.INFO && BlockNum > Node.INFO.BlockNumDB) {
timewait = true
continue;
}
if (Node.TaskLastSend) {
var Delta = CurTime - Node.TaskLastSend;
if (Delta < global.PERIOD_GET_BLOCK) {
timewait = true
continue;
}
}
var keysend = "" + Node.addrStr + ":" + keyid;
if (task.MapSend[keysend])
continue;
Node.TaskLastSend = CurTime
task.time = CurTime
return { Result: true, Node: Node, timewait: timewait };
}
}
if (!task.RestartGetNextNode)
task.RestartGetNextNode = 0
if (!timewait && task.RestartGetNextNode < 3) {
if (!task.LastTimeRestartGetNextNode)
task.LastTimeRestartGetNextNode = 0
var Delta = Date.now() - task.LastTimeRestartGetNextNode;
if (Delta > 3000) {
task.RestartGetNextNode++
task.LastTimeRestartGetNextNode = Date.now()
task.MapSend = {}
return { Result: false, timewait: true };
}
}
return { Result: false, timewait: timewait };
}
SendChainNext(chain: any, checktime: boolean) {
var Ret = this.GetNextNode(chain, chain.BlockNum, checktime);
if (Ret.Result) {
if (!chain.Context)
chain.Context = { Chain: chain }
var Node = Ret.Node;
this.SendF(Node, {
"Method": "GETBLOCKHEADER",
"Context": chain.Context,
"Data": {
Foward: 0,
BlockNum: chain.BlockNum,
Hash: chain.Hash,
IsSum: chain.IsSum,
Count: chain.Count
}
})
var DopStr = "";
if (chain.IsSum)
DopStr = "SUM:"
chain.AddInfo(chain.BlockNum + "/" + DopStr + this.GetStrFromHashShort(chain.Hash) + "->" + global.GetNodeStrPort(Node))
return true;
}
return false;
}
static GETBLOCKHEADER_F() {
return "{\
Foward:byte,\
BlockNum:uint,\
Hash:hash,\
Count:uint,\
IsSum:byte\
}";
}
static GETBLOCKHEADER100_F() {
return "{\
BlockNum:uint,\
Hash:hash,\
Count:uint\
}";
}
GetBlockArrFromBuffer_Load(BufRead: Buffer, Info: SocketSendInfo) {
var BlockArr = global.GetBlockArrFromBuffer(BufRead, Info);
if (BlockArr.length > 0 && BlockArr[0].BlockNum === global.BLOCK_PROCESSING_LENGTH2)
BlockArr.unshift(this.ReadBlockHeaderDB(global.BLOCK_PROCESSING_LENGTH2 - 1))
return BlockArr;
}
RETBLOCKHEADER_FOWARD(Info: SocketSendInfo, CurTime: number) {
if (!Info.Context.Foward)
return;
var Context = this.LoadHistoryContext;
Context.time = undefined
var BufRead = global.BufLib.GetReadBuffer(Info.Data);
var arr = this.GetBlockArrFromBuffer_Load(BufRead, Info);
var arr2 = [];
var bFindDB = 0;
if (arr.length > 1)
for (var i = 0; i < arr.length; i++) {
var Block = arr[i];
if (!Block)
return;
if (Block.BlockNum === global.CHECK_POINT.BlockNum && !global.IsZeroArr(global.CHECK_POINT.Hash)) {
if (global.CompareArr(global.CHECK_POINT.Hash, Block.Hash) !== 0) {
break;
}
Context.FindCheckPoint = true
}
if (Block.BlockNum < this.BlockNumDB) {
break;
}
if (!bFindDB) {
var BlockDB = this.ReadBlockHeaderDB(Block.BlockNum);
if (BlockDB && global.CompareArr(BlockDB.SumHash, Block.SumHash) === 0) {
bFindDB = 1
arr2.push(Block)
}
else
if (BlockDB && global.IsZeroArr(BlockDB.SumHash)) {
bFindDB = 1
arr2.push(Block)
}
}
else
if (bFindDB) {
arr2.push(Block)
}
}
if (arr2.length > 1) {
Context.WasLoadNum = true
var chain = { id: 0, StopSend: true, WriteToDBAfterLoad: true };
this.ChainBindMethods(chain)
this.SetChainNum(chain)
this.PrepareTransactionsForLoad(chain, arr2)
Context.BlockNum = Block.BlockNum
Context.Pause = 1
}
else {
if (!Context.WasLoadNum) {
global.ToLog("Not found: " + Context.BlockNum + " from node:" + global.NodeName(Info.Node), 2)
Context.BlockNum = Math.floor(Context.BlockNum - Context.DeltaBlockNum)
Context.DeltaBlockNum = Context.DeltaBlockNum * 1.2
if (Context.BlockNum < global.BLOCK_PROCESSING_LENGTH2)
Context.BlockNum = global.BLOCK_PROCESSING_LENGTH2 - 1
this.BlockNumDB = Context.BlockNum
this.SetTruncateBlockDB(Context.BlockNum)
}
else {
var keysend = "" + Info.Node.addrStr + ":" + Context.BlockNum;
Context.MapSend[keysend] = 1
}
}
}
RETBLOCKHEADER(Info: SocketSendInfo, CurTime: number) {
Info.Node.NextPing = global.MIN_PERIOD_PING
if (Info.Context.Foward)
return this.RETBLOCKHEADER_FOWARD(Info, CurTime);
var chain = Info.Context.Chain;
if (chain && !chain.StopSend && !chain.Deleted) {
var BufRead = global.BufLib.GetReadBuffer(Info.Data);
chain.time = undefined
var arr = this.GetBlockArrFromBuffer_Load(BufRead, Info);
if (arr.length <= 1) {
var keysend = "" + Info.Node.addrStr + ":" + chain.BlockNum;
chain.MapSend[keysend] = 1
chain.AddInfo("NO:" + global.GetNodeStrPort(Info.Node))
return;
}
chain.AddInfo("L=" + arr.length + " from:" + global.GetNodeStrPort(Info.Node))
var NextLoadBlock;
var PrevBlock;
for (var i = arr.length - 1; i >= 0; i--) {
var Block = arr[i];
var StrKey = global.GetHexFromArr(Block.SumHash);
var MapBlockLoaded = this.GetMapLoaded(Block.BlockNum);
var BlockFind = MapBlockLoaded[StrKey];
if (BlockFind && BlockFind.chain !== chain && BlockFind.chain.Deleted) {
delete MapBlockLoaded[StrKey]
BlockFind = undefined
}
if (!chain.BlockHead)
chain.BlockHead = Block
if (!chain.BlockNumMax)
chain.BlockNumMax = Block.BlockNum
var PrevBlock0 = PrevBlock;
if (BlockFind) {
if (PrevBlock) {
PrevBlock.BlockDown = BlockFind
PrevBlock.Send = undefined
}
PrevBlock = BlockFind
}
else {
if (PrevBlock) {
PrevBlock.BlockDown = Block
PrevBlock.Send = undefined
}
PrevBlock = Block
}
if (BlockFind && BlockFind.chain !== chain) {
chain.ParentChain = BlockFind.chain
chain.RootChain = BlockFind.chain.GetRootChain()
if (chain.RootChain)
chain.RootChain.BlockNumMax = chain.BlockHead.BlockNum
chain.StopSend = true
chain.AddInfo("StopSend - Find load Block")
break;
}
else
if (!BlockFind) {
Block.chain = chain
Block.Node = Info.Node
var StrSumHash = global.GetHexFromArr(Block.SumHash);
MapBlockLoaded[StrSumHash] = Block
var StrHash = global.GetHexFromArr(Block.Hash);
MapBlockLoaded["H:" + StrHash] = Block
var StrTreeHash = global.GetHexFromArr(Block.TreeHash);
MapBlockLoaded["TH:" + StrTreeHash] = Block
var BlockDB = this.ReadBlockHeaderDB(Block.BlockNum);
if (BlockDB) {
Block.Power = global.GetPowPower(Block.PowHash)
chain.LoadCountDB++
chain.LoadSumDB += BlockDB.Power
chain.LoadSum += Block.Power
if (global.CompareArr(BlockDB.SumHash, Block.SumHash) === 0) {
Block.FindBlockDB = true
Block.SumPow = BlockDB.SumPow
chain.FindBlockDB = true
chain.StopSend = true
chain.AddInfo("BlockFind - Find Block in DB")
NextLoadBlock = undefined
break;
}
}
NextLoadBlock = Block
}
}
if (NextLoadBlock && !NextLoadBlock.chain.StopSend) {
if (arr.length >= chain.Count) {
chain.Count = chain.Count * 2
if (chain.Count > global.COUNT_BLOCKS_FOR_LOAD)
chain.Count = global.COUNT_BLOCKS_FOR_LOAD
}
if (chain.LoadCountDB >= global.COUNT_BLOCKS_FOR_CHECK_POW) {
if (chain.LoadSumDB - chain.LoadSum > global.MAX_DELTA_COUNT_SUM_FOR_LOAD) {
var Str = "ERR LOADED SUM POW chains: SumDB > Sum loaded from: " + global.NodeInfo(Info.Node);
chain.StopSend = true
chain.AddInfo(Str)
}
}
if (!chain.StopSend)
this.BlockChainLoad(NextLoadBlock)
}
if (chain.GetFindDB())
this.CheckToStartLoadBlockData(chain)
}
}
BlockChainLoad(Block: TeraBlock) {
var chain = Block.chain;
Block.Send = undefined
chain.BlockNum = Block.BlockNum
chain.Hash = Block.SumHash
chain.IsSum = true
chain.StopSend = false
chain.FindBlockDB = false
chain.RootChain = undefined
chain.ParentChain = undefined
chain.AddInfo("SetChainSend:" + chain.BlockNum)
}
CheckToStartLoadBlockData(chain: TeraChain) {
if (chain.Deleted)
return;
var arr = this.GetArrFromChain(chain);
if (arr.length < 2)
return;
var BlockMax = arr[arr.length - 1];
var BlockMin = arr[0];
var PrevBlock = BlockMin;
for (var i = 1; i < arr.length; i++) {
var Block = arr[i];
Block.Power = global.GetPowPower(Block.PowHash)
Block.SumPow = PrevBlock.SumPow + Block.Power
PrevBlock = Block
}
var BlockNow = this.ReadBlockHeaderDB(BlockMax.BlockNum);
if (BlockNow && (BlockMax.SumPow < BlockNow.SumPow || BlockMax.SumPow === BlockNow.SumPow && global.CompareArr(BlockMax.PowHash, BlockNow.PowHash) < 0)) {
var Str = "Low SumPow";
chain.AddInfo(Str)
return;
}
var Str = "Start Load blocks: " + (BlockMin.BlockNum + 1) + " - " + BlockMax.BlockNum;
chain.AddInfo(Str)
this.PrepareTransactionsForLoad(chain, arr)
}
GetArrFromChain(chain: TeraChain) {
var arr = [];
var Block = chain.BlockHead;
while (Block) {
arr.unshift(Block)
if (Block.AddToLoad || Block.FindBlockDB || Block.LoadDBFinaly) {
break;
}
Block = Block.BlockDown
}
return arr;
}
PrepareTransactionsForLoad(chain: TeraChain, arr: any[], bNoSlice?: boolean) {
if (!bNoSlice)
arr = arr.slice(1)
chain.arr = arr
if (arr.length > 0) {
for (var i = 0; i < arr.length; i++)
arr[i].AddToLoad = 1
chain.CurNumArrLoad = 0
}
}
LoopBlockLoad() {
if (global.glStopNode)
return;
var CountSend = 0;
for (var num = 0; num < this.LoadedChainList.length; num++) {
var chain = this.LoadedChainList[num];
if (chain && chain.arr && chain.arr.length && chain.StopSend) {
var Count = 0;
for (var i = chain.CurNumArrLoad; i < chain.arr.length; i++) {
Count++
var Block = chain.arr[i];
if (!global.IsZeroArr(Block.TreeHash) && !Block.TreeEq && !Block.LoadDBFinaly) {
if (!Block.MapSend) {
if (!Block.BodyLoad) {
var BlockDB = this.ReadBlockHeaderDB(Block.BlockNum);
if (BlockDB) {
if (global.CompareArr(BlockDB.TreeHash, Block.TreeHash) == 0) {
Block.TreeEq = true
Block.Reserv500 = BlockDB.Reserv500
Block.TrDataPos = BlockDB.TrDataPos
Block.TrDataLen = BlockDB.TrDataLen
continue;
}
}
}
Block.MapSend = {}
}
if (this.SendBlockNext(Block)) {
CountSend++
if (CountSend >= global.MAX_BLOCK_SEND)
return;
}
} else {
if (i === chain.CurNumArrLoad) {
chain.CurNumArrLoad++
Block.LoadDBFinaly = true
Count = 0
}
}
}
this.CheckAndWriteLoadedChain(chain)
}
}
}
CheckAndWriteLoadedChain(chain: TeraChain) {
if (chain.CurNumArrLoad >= chain.arr.length) {
var Block = chain.arr[chain.arr.length - 1];
if (chain.WriteToDBAfterLoad || Block.BlockNum >= this.CurrentBlockNum + global.TIME_START_SAVE - 2) {
var bAllLoaded = true;
if (!chain.WriteToDBAfterLoad) {
var cur_parent = chain.ParentChain;
while (cur_parent) {
if (cur_parent.arr && cur_parent.CurNumArrLoad < cur_parent.arr.length) {
bAllLoaded = false
break;
}
cur_parent = cur_parent.ParentChain
}
}
if (bAllLoaded) {
var arr = [];
var cur_chain = chain;
while (cur_chain) {
if (cur_chain.arr)
for (var i = cur_chain.arr.length - 1; i >= 0; i--) {
var Block = cur_chain.arr[i];
arr.unshift(Block)
}
cur_chain = cur_chain.ParentChain
}
this.WriteLoadedBlockArr(arr)
}
}
}
}
WriteLoadedBlockArr(arr: TeraBlock[]) {
if (!arr.length)
return;
var startTime = process.hrtime();
if (this.LoadHistoryMessage)
global.ToLog("WRITE DATA Count:" + arr.length + " " + arr[0].BlockNum + "-" + arr[arr.length - 1].BlockNum, 2)
var CurrentBlockNum = global.GetCurrentBlockNumByTime();
var Block, FirstBlock;
for (var i = 0; i < arr.length; i++) {
Block = arr[i]
if (Block.BlockNum > this.BlockNumDB + 1)
break;
if (!FirstBlock)
FirstBlock = Block
Block.BlockDown = undefined
if (Block.BlockNum > this.BlockNumDBMin + global.BLOCK_PROCESSING_LENGTH2) {
var PrevHash = this.GetPrevHashDB(Block);
if (global.CompareArr(PrevHash, Block.PrevHash) !== 0) {
if (global.WATCHDOG_DEV)
global.ToError("******** ERROR LOADED DATA Count:" + arr.length + " AT BLOCK NUM:" + Block.BlockNum + " (" + arr[0].BlockNum + "-" + arr[arr.length - 1].BlockNum + ")")
this.FREE_ALL_MEM_CHAINS()
return;
}
}
var Res: any = 0;
if (Block.TreeEq) {
this.ReadBlockBodyDB(Block)
Res = this.WriteBlockDBFinaly(Block)
}
else {
if (global.IsZeroArr(Block.TreeHash)) {
Res = this.WriteBlockDB(Block)
} else {
global.ToLogTrace("IsZeroArr(Block.TreeHash)")
throw "IsZeroArr(Block.TreeHash)";
}
}
if (!Res) {
global.ToLog("ERROR WRITE DB, NUM=" + Block.BlockNum)
this.FREE_ALL_MEM_CHAINS()
return;
}
Block.LoadDB = true
if (Block.BlockNum >= CurrentBlockNum - global.BLOCK_COUNT_IN_MEMORY) {
this.CopyBlockToMem(Block)
}
else {
if (Block.arrContent)
Block.arrContent.length = 0
Block.arrContent = undefined
}
var BlockMem = this.BlockChain[Block.BlockNum];
if (BlockMem) {
global.AddInfoBlock(BlockMem, "LOAD:" + global.GetPowPower(Block.PowHash) + " TH:" + this.GetStrFromHashShort(Block.TreeHash).substr(0, 4))
}
}
if (Block && FirstBlock) {
var CurNumStart = Math.max(FirstBlock.BlockNum + 8, Block.BlockNum + 1);
this.SetNoPOW(CurNumStart, 1, FirstBlock.BlockNum)
}
this.FREE_ALL_MEM_CHAINS()
global.ADD_TO_STAT_TIME("WRITECHAIN_TO_DB_TIME", startTime)
}
SetNoPOW(BlockNumFrom: number, bReload: number, RefBlockNum: any) {
//defiend in block-exchange.js
}
CopyBlock(Block: TeraBlock, BlockDst: TeraBlock) {
BlockDst.BlockNum = Block.BlockNum
BlockDst.TreeHash = Block.TreeHash
BlockDst.AddrHash = Block.AddrHash
BlockDst.PrevHash = Block.PrevHash
BlockDst.SumHash = Block.SumHash
BlockDst.SumPow = Block.SumPow
BlockDst.TrDataPos = Block.TrDataPos
BlockDst.TrDataLen = Block.TrDataLen
BlockDst.SeqHash = Block.SeqHash
BlockDst.Hash = Block.Hash
BlockDst.PowHash = Block.PowHash
BlockDst.TrCount = Block.TrCount
BlockDst.arrContent = Block.arrContent
BlockDst.bSave = Block.bSave
}
CopyBlockToMem(Block: TeraBlock) {
var BlockMem = this.BlockChain[Block.BlockNum];
if (BlockMem) {
this.CopyBlock(Block, BlockMem)
BlockMem.Prepared = true
BlockMem.MinTrPow = undefined
this.RecreateMaxPOW(BlockMem)
}
this.AddToStatBlockConfirmation(Block)
}
RecreateMaxPOW(Block: TeraBlock) {
//defiend in block-exchange.js
}
ClearMaxInBlock(Block: TeraBlock) {
Block.MaxPOW = {}
var POW = Block.MaxPOW;
POW.SeqHash = Block.SeqHash
POW.AddrHash = Block.AddrHash
POW.PrevHash = Block.PrevHash
POW.TreeHash = Block.TreeHash
POW.Hash = Block.Hash
POW.PowHash = Block.PowHash
POW.SumPow = Block.SumPow
Block.MaxSum = {}
POW = Block.MaxSum
POW.SeqHash = Block.SeqHash
POW.AddrHash = Block.AddrHash
POW.PrevHash = Block.PrevHash
POW.TreeHash = Block.TreeHash
POW.Hash = Block.Hash
POW.PowHash = Block.PowHash
POW.SumHash = Block.SumHash
POW.SumPow = Block.SumPow
}
AddToStatBlockConfirmation(Block: TeraBlock) {
if (Block.BlockNum > global.START_BLOCK_RUN + global.BLOCK_PROCESSING_LENGTH2) {
var TimeDelta = this.CurrentBlockNum - Block.BlockNum;
global.ADD_TO_STAT("MAX:BlockConfirmation", TimeDelta)
}
else {
global.ADD_TO_STAT("MAX:BlockConfirmation", global.BLOCK_PROCESSING_LENGTH)
}
}
SendBlockNext(Block: TeraBlock & ContextTask) {
var SendResult = 0;
var Key = global.GetHexFromArr(Block.TreeHash);
while (true) {
var Ret = this.GetNextNode(Block, Key, true, Block.BlockNum);
if (Ret.Result) {
var Node = Ret.Node;
if (!Block.Context)
Block.Context = { Block: Block }
this.SendF(Node, { "Method": "GETBLOCK", "Context": Block.Context, "Data": { BlockNum: Block.BlockNum, TreeHash: Block.TreeHash } })
Node.SendBlockCount++
SendResult = 1
global.AddInfoBlock(Block, "SendNext")
if (Block.chain)
Block.chain.AddInfo("QUERY BL:" + Block.BlockNum + "/" + this.GetStrFromHashShort(Block.TreeHash) + " TO:" + global.GetNodeStrPort(Node))
}
else {
if (!Ret.timewait) {
this.ClearChains(Block.chain, true)
}
}
break;
}
return SendResult;
}
ClearChains(DeleteChain: TeraChain, bShow?: boolean) {
if (!DeleteChain) {
this.FREE_ALL_MEM_CHAINS()
return this.LoadedChainList.length;
}
var allsum = this.LoadedChainList.length;
var Sum = 0;
for (var i = 0; i < this.LoadedChainList.length; i++) {
var chain = this.LoadedChainList[i];
if (chain) {
if (chain === DeleteChain) {
chain.Deleted = true
this.LoadedChainList[i] = undefined
Sum++
}
if (chain.ParentChain === DeleteChain) {
Sum += this.ClearChains(chain)
}
}
}
if (bShow) {
global.ToLog("===========ClearChains================= " + DeleteChain.id + " count=" + Sum + "/" + allsum)
}
return Sum;
}
RecalcLoadBlockStatictic() {
return;
var TimeNum = Math.floor(Date.now() / STAT_BLOCK_LOAD_PERIOD);
if (this.LoadBlockStatNum === TimeNum)
return;
this.LoadBlockStatNum = TimeNum
const PeriodSec = 5;
const Period = global.CONSENSUS_PERIOD_TIME / STAT_BLOCK_LOAD_PERIOD;
const PeriodCount = PeriodSec * Period;
var FreeGet = 64;
var it = this.ActualNodes.iterator(), Node;
while ((Node = it.next()) !== null) {
var arr = Node.SendBlockArr;
arr.push(Node.SendBlockCount)
if (arr.length > PeriodCount) {
arr.shift()
}
arr = Node.LoadBlockArr
arr.push(Node.LoadBlockCount)
if (arr.length > PeriodCount) {
arr.shift()
}
var SendPackets = 0;
var LoadPackets = 0;
for (var i = 0; i < Node.SendBlockArr.length; i++)
SendPackets += Node.SendBlockArr[i]
for (var i = 0; i < Node.LoadBlockArr.length; i++)
LoadPackets += Node.LoadBlockArr[i]
Node.SendBlockCountAll = SendPackets
Node.LoadBlockCountAll = LoadPackets
var Nuts = Math.floor(LoadPackets / PeriodSec);
var RestPackets = SendPackets - LoadPackets;
var CountGet = 1 + Math.floor(Math.max(0, (Nuts - RestPackets / Period)));
Node.CanGetBlocks = Math.min(FreeGet, CountGet)
FreeGet -= Node.CanGetBlocks
Node.SendBlockCount = 0
Node.LoadBlockCount = 0
global.ADD_TO_STAT("NODE_CAN_GET:" + global.NodeName(Node), Node.CanGetBlocks, 1)
}
}
static GETBLOCK_F() {
return "{\
BlockNum:uint,\
TreeHash:hash,\
}";
}
RETGETBLOCK(Info: SocketSendInfo, CurTime: number) {
Info.Node.NextPing = global.MIN_PERIOD_PING
var Block = Info.Context.Block;
if (Block && !Block.TreeEq) {
var Data = global.BufLib.GetObjectFromBuffer(Info.Data, DB_FORMAT.FORMAT_BLOCK_TRANSFER, global.WRK_BLOCK_TRANSFER);
Info.Data = undefined
if (Data.BlockNum !== Block.BlockNum || global.CompareArr(Data.TreeHash, Block.TreeHash) !== 0) {
this.SetBlockNOSendToNode(Block, Info.Node, "NO")
return;
}
if (Block.chain) {
Block.chain.AddInfo("Load TR:" + Data.BlockNum + "/" + this.GetStrFromHashShort(Data.TreeHash) + " from:" + global.GetNodeStrPort(Info.Node))
global.AddInfoBlock(Block, "LOAD TR OK")
}
var arrContent = Data.arrContent;
var TreeHash = global.CalcTreeHashFromArrBody(Block.BlockNum, arrContent);
if (global.CompareArr(Block.TreeHash, TreeHash) !== 0) {
global.ToLog("2. BAD CMP TreeHash block=" + Block.BlockNum + " from:" + global.NodeName(Info.Node) + " TreeHash=" + global.GetHexFromArr(TreeHash) + " BlockTreeHash=" + global.GetHexFromArr(Block.TreeHash))
this.SetBlockNOSendToNode(Block, Info.Node, "BAD CMP TreeHash")
return;
}
if (arrContent.length > 0 && Data.BlockNum % global.PERIOD_ACCOUNT_HASH === 0) {
var TR = arrContent[0];
if (TR[0] === TYPE_TRANSACTION.TYPE_TRANSACTION_ACC_HASH) {
if (!global.DApps.Accounts.TRCheckAccountHash(TR, Data.BlockNum)) {
if (!this.BADHashCount)
this.BADHashCount = 0
this.BADHashCount++
global.ToLog("**** BAD ACCOUNT Hash in block=" + Block.BlockNum + " from:" + global.NodeName(Info.Node) + " ****")
global.ToLog("May be need to Rewrite transactions from: " + (Block.BlockNum - 2 * global.DELTA_BLOCK_ACCOUNT_HASH))
this.SetBlockNOSendToNode(Block, Info.Node, "BAD CMP ACC HASH")
if (global.WATCHDOG_BADACCOUNT && this.BADHashCount > 60) {
global.ToLog("Run WATCHDOG!")
this.BADHashCount = 0
this.FREE_ALL_MEM_CHAINS()
this.SetTruncateBlockDB(Block.BlockNum - 5 * global.DELTA_BLOCK_ACCOUNT_HASH)
}
return;
}
}
}
Block.arrContent = arrContent
var Ret = this.WriteBodyDB(Block);
Block.TrCount = 0
Block.arrContent.length = 0
Block.arrContent = undefined
if (!Ret) {
this.SetBlockNOSendToNode(Block, Info.Node, "Error write")
return;
}
Block.TreeEq = true
Block.Send = undefined
global.ADD_TO_STAT("BLOCK_LOADED", 1)
Info.Node.LoadBlockCount++
if (global.GrayConnect())
Info.Node.BlockProcessCount++
if (this.LoadHistoryMode) {
var Context = this.LoadHistoryContext;
Context.PrevBlockNum = Context.BlockNum
Context.StartTimeHistory = Date.now()
}
}
}
SendCanBlock(Node: CNode, Block: TeraBlock) {
Node.SendBlockCount++
if (!Node.INFO.BlockNumDB)
return;
if (Node.INFO.BlockNumDB >= Block.BlockNum) {
this.SendF(Node, { "Method": "CANBLOCK", "Data": { BlockNum: Block.BlockNum } })
}
}
static CANBLOCK_F() {
return "{BlockNum:uint}";
}
CANBLOCK(Info: SocketSendInfo, CurTime: number) {
var Data = this.DataFromF(Info);
this.SendF(Info.Node, { "Method": "RETCANBLOCK", "Data": { Result: 1 } })
}
static RETCANBLOCK_F() {
return "{Result:byte}";
}
RETCANBLOCK(Info: SocketSendInfo, CurTime: number) {
var Data = this.DataFromF(Info);
if (Data.Result === 1) {
Info.Node.LoadBlockCount++
}
}
DataFromF(Info: SocketSendInfo, bSendFormat?: boolean): any {
//defiend in server.js
}
SetBlockNOSendToNode(Block: TeraBlock, Node: CNode, Str) {
var Str = global.GetHexFromArr(Block.TreeHash);
var Str2 = this.GetStrFromHashShort(Block.TreeHash);
var keysend = "" + Node.addrStr + ":" + Str;
Block.MapSend[keysend] = 1
if (Block.chain)
Block.chain.AddInfo("" + Block.BlockNum + " " + Str2 + "<-" + global.GetNodeStrPort(Node))
}
FindBlockInLoadedChain(BlockNum: number, TreeHash: Buffer) {
var StrTreeHash = global.GetHexFromArr(TreeHash);
var MapBlockLoaded = this.GetMapLoaded(BlockNum);
var BlockFind = MapBlockLoaded["TH:" + StrTreeHash];
if (BlockFind && BlockFind.TreeEq)
return BlockFind;
else
return undefined;
}
CheckSeqHashDB(Block: TeraBlock, StrError: string) {
if (Block.BlockNum < global.BLOCK_PROCESSING_LENGTH2)
return true;
var TreeHashTest = global.CalcTreeHashFromArrBody(Block.BlockNum, Block.arrContent);
if (global.CompareArr(TreeHashTest, Block.TreeHash) !== 0) {
var StrHex = global.GetHexFromArr(TreeHashTest);
var StrHex0 = global.GetHexFromArr(Block.TreeHash);
var Str = StrError + " #3 ERROR TREEHASH: " + Block.BlockNum + " Hex:" + StrHex0.substr(0, 12) + " != " + StrHex.substr(0,
12);
if (global.WATCHDOG_DEV)
global.ToErrorTrace(Str)
else
global.ToError(Str)
return false;
}
var PrevHash = this.GetPrevHashDB(Block);
var testSeqHash = this.GetSeqHash(Block.BlockNum, PrevHash, Block.TreeHash);
var TestValue = global.GetHashFromSeqAddr(testSeqHash, Block.AddrHash, Block.BlockNum, PrevHash);
if (global.CompareArr(TestValue.Hash, Block.Hash) !== 0) {
var Str = StrError + " #2 ERROR HASH - block num: " + Block.BlockNum;
if (global.WATCHDOG_DEV)
global.ToErrorTrace(Str)
else
global.ToError(Str)
return false;
}
return true;
}
ToLogBlock(Block: TeraBlock, StrInfo: string, arr: any[]) {
global.ToLog("-------------" + StrInfo)
global.ToLog("BlockNum=" + (Block.BlockNum))
global.ToLog("Hash=" + global.GetHexFromArr(Block.Hash))
global.ToLog("SeqHash=" + global.GetHexFromArr(Block.SeqHash))
global.ToLog("PrevHash=" + global.GetHexFromArr(Block.PrevHash))
global.ToLog("TreeHash=" + global.GetHexFromArr(Block.TreeHash))
global.ToLog("AddrHash=" + global.GetHexFromArr(Block.AddrHash))
global.ToLog("SumHash=" + global.GetHexFromArr(Block.SumHash))
global.ToLog("SumPow=" + Block.SumPow)
for (var i = 0; i < arr.length; i++) {
global.ToLog("arr[" + i + "]=" + global.GetHexFromArr(arr[i]))
}
}
GetBlock(num: number, bToMem?: boolean, bReadBody?: boolean) {
if (bToMem === undefined)
bToMem = true
if (num < this.CurrentBlockNum - global.BLOCK_COUNT_IN_MEMORY)
bToMem = false
var Block = this.BlockChain[num];
if (!Block) {
if (bReadBody)
Block = this.ReadBlockDB(num)
else
Block = this.ReadBlockHeaderDB(num)
if (bToMem) {
this.BlockChain[num] = Block
}
}
return Block;
}
GetMapLoaded(num: number) {
if (num < 0)
num = 0
var index = Math.floor(num / global.BLOCK_COUNT_IN_MEMORY);
var map = this.MapMapLoaded[index];
if (!map) {
map = {}
this.MapMapLoaded[index] = map
}
return map;
}
GetMapLoadedFromChain(chain: TeraChain) {
return this.GetMapLoaded(chain.BlockNumStart);
}
FREE_MEM_BLOCKS(NumMax: number) {
for (var key in this.BlockChain) {
var Block = this.BlockChain[key];
if (!Block || Block.BlockNum < NumMax) {
delete this.BlockChain[key]
}
}
}
FREE_MEM_CHAINS(NumMax: number) {
this.FREE_MEM_BLOCKS(NumMax - global.BLOCK_COUNT_IN_MEMORY)
var maxArrMap = Math.floor(NumMax / global.BLOCK_COUNT_IN_MEMORY) - 1;
if (maxArrMap >= 0) {
var nWasCount = 0;
for (var key in this.MapMapLoaded)
if (key as any < maxArrMap) {
nWasCount++
delete this.MapMapLoaded[key]
}
}
}
FREE_ALL_MEM_CHAINS() {
this.FREE_MEM_BLOCKS(this.BlockNumDB - global.BLOCK_COUNT_IN_MEMORY)
for (var i = 0; i < this.LoadedChainList.length; i++) {
var chain = this.LoadedChainList[i];
if (chain) {
chain.Deleted = true
chain.ChainMax = undefined
}
}
if (!this.LoadHistoryMode) {
this.AddValueToHistory("LoadedChainList", this.LoadedChainList)
this.AddValueToHistory("MapMapLoaded", this.MapMapLoaded)
}
this.LoadedChainList = []
this.MapMapLoaded = {}
//@ts-ignore
if (typeof gc === "function")
//@ts-ignore
gc()
}
AddValueToHistory(typedata: string, val: any) {
var Arr = global.HistoryBlockBuf.LoadValue(typedata, 1);
if (!Arr) {
Arr = []
global.HistoryBlockBuf.SaveValue(typedata, Arr)
}
Arr.push(val)
}
GetHistoryTree(typedata: string) {
var Tree = global.HistoryBlockBuf.LoadValue(typedata, 1);
if (!Tree) {
Tree = new RBTree(global.CompareItemHash)
global.HistoryBlockBuf.SaveValue(typedata, Tree)
}
return Tree;
}
ChainBindMethods(chain: TeraChain) {
function GetRootChain() {
var Count = 0;
var root_chain = this;
while (root_chain.RootChain) {
Count++
root_chain = root_chain.RootChain
if (Count > global.MAX_COUNT_CHAIN_LOAD) {
global.TO_ERROR_LOG("BLOCK", 10, "Error COUNT GetRootChain")
global.SERVER.FREE_ALL_MEM_CHAINS()
return undefined;
}
}
return root_chain;
};
function GetFindDB() {
var Root = this.GetRootChain();
if (Root)
return Root.FindBlockDB;
else
return false;
};
chain.GetRootChain = GetRootChain.bind(chain)
chain.GetFindDB = GetFindDB.bind(chain)
chain.AddInfo = global.AddInfoChain.bind(chain)
}
GetMemoryStamp(Str: string) {
return Str + ":##:" + Math.floor(this.CurrentBlockNum / global.BLOCK_COUNT_IN_MEMORY);
}
GetStrFromHashShort(Hash: Buffer) {
var Str = global.GetHexFromArr(Hash);
if (typeof Str === "string")
return Str.substr(0, 6);
else
return "";
}
ToLogTime(startTime: [number, number], Str: string) {
const Time = process.hrtime(startTime);
var deltaTime = (Time[0] * 1000 + Time[1] / 1e6);
global.ToLog(Str + " : " + deltaTime + "ms")
}
AddBlockToLoadBody(Block: TeraBlock) {
if (!this.MapBlockBodyLoad[Block.BlockNum]) {
this.MapBlockBodyLoad[Block.BlockNum] = Block
}
}
LoopBlockBodyLoad() {
var arr = [];
for (var key in this.MapBlockBodyLoad) {
var Block = this.MapBlockBodyLoad[key];
if (!Block.BodyLoad) {
Block.BodyLoad = 1
arr.push(Block)
}
}
this.MapBlockBodyLoad = {}
if (!arr.length)
return;
var chain = { StopSend: true, WriteToDBAfterLoad: true, BodyLoad: true };
this.ChainBindMethods(chain)
this.SetChainNum(chain)
this.PrepareTransactionsForLoad(chain, arr, true)
}
};
global.LoadBlockFromNetwork = function(Params, F) {
var BlockNum = Params.BlockNum;
if (BlockNum >= global.SERVER.BlockNumDBMin) {
global.ToLog("Cant LoadBlockFromNetwork:" + BlockNum, 2);
F(1);
return;
}
global.ToLog("Start DownloadBlockFromNetwork:" + BlockNum, 2);
var TaskLoadBlockFromNetwork = { MapSend: {} };
var Ret = global.SERVER.GetNextNode(TaskLoadBlockFromNetwork, BlockNum, 1);
if (Ret.Result) {
let Node = Ret.Node;
global.SERVER.SendF(Node, {
"Method": "GETBLOCK", "Data": { BlockNum: BlockNum, TreeHash: [] }, "Context": {
F: function(Info) {
var Block = global.BufLib.GetObjectFromBuffer(Info.Data, DB_FORMAT.FORMAT_BLOCK_TRANSFER, global.WRK_BLOCK_TRANSFER);
Info.Data = undefined;
if (!Block.BlockNum || Block.BlockNum !== Params.BlockNum) {
global.ToLog("Error get BlockNum:" + Params.BlockNum + " from " + global.NodeName(Info.Node), 2);
F(1);
return;
}
global.ToLog("Got BlockFromNetwork:" + Params.BlockNum + " from " + global.NodeName(Info.Node), 2);
var ResError;
if (!Block.arrContent || Block.arrContent.length === 0) {
ResError = 1;
} else {
ResError = 0;
global.SERVER.WriteBlockDB(Block);
}
F(ResError, Block);
}
},
});
}
else {
global.ToLog("Not find node for download block", 2);
F(1);
}
};
global.HistoryBlockBuf = new STreeBuffer(global.HISTORY_BLOCK_COUNT * 1000, global.CompareItemHashSimple, "string");