/* * @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 DBLib from './db' import DBRow from './db-row' global.BlockDB = new DBLib(); global.BLOCK_HEADER_SIZE = 150; const FILE_NAME_HEADER = "block-header"; const FILE_NAME_BODY = "block-body"; const FORMAT_STREAM_HEADER = "{\ VersionDB:byte,\ TreeHash:hash,\ AddrHash:hash,\ PrevHash:hash,\ SumHash:hash,\ SumPow:uint,\ TrDataPos:uint,\ TrDataLen:uint32,\ Reserv500:uint\ }"; const WorkStructStreamHeader = {}; global.BLOCK_HEADER_SIZE2 = 6; const FORMAT_HEADER_VERSION2 = "{FilePos:uint}"; const FILE_NAME_HEADER2 = "block-header2"; const WorkStructHeader2 = {}; const DEFAULT_DB_VERSION = 2; import CCode from '../code' export default class CDB extends CCode { DBHeader100: DBRow BlockNumDB: number BlockNumDBMin: number CurrentBlockNum CheckOnStartComplete UseTruncateBlockDB MapHeader StatMap PrevBlockChainArr constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) { super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) var bWriteMode = (global.PROCESS_NAME === "MAIN"); global.DB_VERSION = DEFAULT_DB_VERSION var FileItem1 = global.BlockDB.OpenDBFile(FILE_NAME_HEADER, bWriteMode); var FileItem2 = global.BlockDB.OpenDBFile(FILE_NAME_HEADER2, bWriteMode); if (FileItem2.size) global.DB_VERSION = 2 else if (FileItem1.size) global.DB_VERSION = 1 global.BlockDB.OpenDBFile(FILE_NAME_BODY, bWriteMode) this.DBHeader100 = new DBRow("block-header100", 32 + 32, "{Hash100:hash,Hash:hash}", !bWriteMode) this.BlockNumDB = 0 this.BlockNumDBMin = 0 this.ClearBufMap() setTimeout(function() { global.SERVER.ReadStateTX() }, 10) } ReadStateTX() { var StateTX = global.DApps.Accounts.DBStateTX.Read(0); if (StateTX) { this.BlockNumDBMin = StateTX.BlockNumMin } } GetBlock(num, bToMem, bReadBody): any { //defiend in block-loader.ts(CBlock) } LoadMemBlocksOnStart() { this.CurrentBlockNum = global.GetCurrentBlockNumByTime() for (var i = this.BlockNumDB - global.BLOCK_COUNT_IN_MEMORY; i <= this.BlockNumDB; i++) if (i >= 0) { if (i >= this.BlockNumDB - global.BLOCK_PROCESSING_LENGTH * 5) this.GetBlock(i, true, true) else this.GetBlock(i, true, false) } } GetMaxNumBlockDB() { var FileItem, BlockNum; if (global.DB_VERSION === 2) { FileItem = global.BlockDB.OpenDBFile(FILE_NAME_HEADER2) BlockNum = (FileItem.size / global.BLOCK_HEADER_SIZE2) - 1 } else { FileItem = global.BlockDB.OpenDBFile(FILE_NAME_HEADER) BlockNum = (FileItem.size / global.BLOCK_HEADER_SIZE) - 1 } return BlockNum; } FindStartBlockNum() { this.ReadStateTX() var BlockNum = this.GetMaxNumBlockDB(); if (global.NO_CHECK_BLOCKNUM_ONSTART) { this.BlockNumDB = this.CheckBlocksOnStartFoward(BlockNum - 2, 0) global.ToLog("START_BLOCK_NUM:" + this.BlockNumDB, 2) return; } BlockNum = this.CheckBlocksOnStartReverse(BlockNum) this.BlockNumDB = this.CheckBlocksOnStartFoward(BlockNum - 2000, 0) this.BlockNumDB = this.CheckBlocksOnStartFoward(this.BlockNumDB - 100, 1) if (this.BlockNumDB >= global.BLOCK_PROCESSING_LENGTH2) { this.TruncateBlockDB(this.BlockNumDB) } global.ToLog("START_BLOCK_NUM:" + this.BlockNumDB, 2) this.CheckOnStartComplete = 1 } CheckBlocksOnStartReverse(StartNum) { var delta = 1; var Count = 0; var PrevBlock; for (var num = StartNum; num >= this.BlockNumDBMin + global.BLOCK_PROCESSING_LENGTH2; num -= delta) { var Block = this.ReadBlockHeaderDB(num); if (!Block || global.IsZeroArr(Block.SumHash)) { delta++ Count = 0 continue; } var PrevBlock = this.ReadBlockHeaderDB(num - 1); if (!PrevBlock || global.IsZeroArr(PrevBlock.SumHash)) { Count = 0 continue; } var SumHash = global.shaarr2(PrevBlock.SumHash, Block.Hash); if (global.CompareArr(SumHash, Block.SumHash) === 0) { delta = 1 Count++ if (Count > global.COUNT_BLOCKS_FOR_LOAD / 10) return num; } else { delta++ Count = 0 } } return 0; } CheckBlocksOnStartFoward(StartNum, bCheckBody) { var PrevBlock; if (StartNum < this.BlockNumDBMin + global.BLOCK_PROCESSING_LENGTH2) StartNum = this.BlockNumDBMin + global.BLOCK_PROCESSING_LENGTH2 var MaxNum = global.DApps.Accounts.GetHashedMaxBlockNum(); var BlockNumTime = global.GetCurrentBlockNumByTime(); if (BlockNumTime < MaxNum) MaxNum = BlockNumTime var arr = []; for (var num = StartNum; num <= MaxNum; num++) { var Block; if (bCheckBody) Block = this.ReadBlockDB(num) else Block = this.ReadBlockHeaderDB(num) if (!Block) return num > 0 ? num - 1 : 0; if (num % 100000 === 0) global.ToLog("CheckBlocksOnStartFoward: " + num) if (bCheckBody) { var TreeHash = global.CalcTreeHashFromArrBody(Block.BlockNum, Block.arrContent); if (global.CompareArr(Block.TreeHash, TreeHash) !== 0) { global.ToLog("BAD TreeHash block=" + Block.BlockNum) return num > 0 ? num - 1 : 0; } } if (PrevBlock) { if (arr.length !== global.BLOCK_PROCESSING_LENGTH) { var start = num - global.BLOCK_PROCESSING_LENGTH2; for (var n = 0; n < global.BLOCK_PROCESSING_LENGTH; n++) { var Prev = this.ReadBlockHeaderDB(start + n); arr.push(Prev.Hash) } } else { arr.shift() var Prev = this.ReadBlockHeaderDB(num - global.BLOCK_PROCESSING_LENGTH - 1); arr.push(Prev.Hash) } var PrevHash = global.CalcHashFromArray(arr, true); var SeqHash = this.GetSeqHash(Block.BlockNum, PrevHash, Block.TreeHash); var Value = global.GetHashFromSeqAddr(SeqHash, Block.AddrHash, Block.BlockNum, PrevHash); if (global.CompareArr(Value.Hash, Block.Hash) !== 0) { global.ToLog("=================== FIND ERR Hash in " + Block.BlockNum + " bCheckBody=" + bCheckBody) return num > 0 ? num - 1 : 0; } var SumHash = global.shaarr2(PrevBlock.SumHash, Block.Hash); if (global.CompareArr(SumHash, Block.SumHash) !== 0) { global.ToLog("=================== FIND ERR SumHash in " + Block.BlockNum) return num > 0 ? num - 1 : 0; } } PrevBlock = Block } return num > 0 ? num - 1 : 0; } WriteBlockDB(Block) { var startTime = process.hrtime(); if (Block.TrCount === 0 && !global.IsZeroArr(Block.TreeHash)) { global.ToLogTrace("ERROR WRITE TrCount BLOCK:" + Block.BlockNum) throw "ERROR WRITE"; } var Ret = this.WriteBodyDB(Block); if (Ret) { Ret = this.WriteBlockDBFinaly(Block) } global.ADD_TO_STAT_TIME("MAX:WriteBlockDB", startTime) global.ADD_TO_STAT_TIME("WriteBlockDB", startTime) return Ret; } WriteBlockDBFinaly(Block) { var Ret = this.WriteBlockHeaderDB(Block); if (Ret) { if (Block.TrDataLen === 0 && !global.IsZeroArr(Block.TreeHash)) { global.ToLogTrace("ERROR WRITE FINAL TrDataLen BLOCK") throw "ERROR WRITE"; } this.OnWriteBlock(Block) if (Block.BlockNum > this.BlockNumDBMin) this.BlockNumDB = Block.BlockNum Block.bSave = true } return Ret; } OnWriteBlock(Block) { //defiend in transaction-validator.ts(CSmartContract) } PreSaveDataTreeToDB(Block) { var Ret = this.WriteBodyDB(Block); if (Ret) { Ret = this.WriteBlockHeaderDB(Block, 1) } return Ret; } WriteBodyResultDB(Block) { var arrTr = Block.arrContentResult; if (Block.TrDataPos && Block.TrDataLen && Block.VersionBody && arrTr && arrTr.length) { var FileItem = global.BlockDB.OpenDBFile(FILE_NAME_BODY, 1); var FD = FileItem.fd; var Size = arrTr.length * 6; var Position = Block.TrDataPos + Block.TrDataLen - Size; if (FileItem.size < Position + Size) { global.TO_ERROR_LOG("DB", 241, "Error Position in WriteBodyResultDB on block: " + Block.BlockNum) return false; } var BufWrite = global.BufLib.GetNewBuffer(Size); for (var i = 0; i < arrTr.length; i++) { BufWrite.Write(arrTr[i], "uint") } var written = fs.writeSync(FD, BufWrite, 0, BufWrite.length, Position); if (written !== BufWrite.length) { global.TO_ERROR_LOG("DB", 242, "Error write to file block-chain : " + written + " <> " + BufWrite.length) return false; } } return true; } WriteBodyDB(Block) { var FileItem = global.BlockDB.OpenDBFile(FILE_NAME_BODY, 1); var FD = FileItem.fd; var Position = FileItem.size; Block.TrDataPos = Position var arrTr = Block.arrContent; if (!arrTr || arrTr.length === 0) { Block.TrCount = 0 Block.TrDataLen = 0 return true; } var TrDataLen = 4; var arrSize = []; for (var i = 0; i < arrTr.length; i++) { var body = arrTr[i]; arrSize[i] = 2 + body.length TrDataLen += arrSize[i] } Block.VersionBody = 1 TrDataLen += arrTr.length * 6 var BufWrite = global.BufLib.GetNewBuffer(TrDataLen); BufWrite.Write(arrTr.length, "uint16") BufWrite.Write(Block.VersionBody, "uint16") for (var i = 0; i < arrTr.length; i++) { var body = arrTr[i]; BufWrite.Write(body, "tr") } var written = fs.writeSync(FD, BufWrite, 0, BufWrite.length, Position); if (written !== BufWrite.length) { global.TO_ERROR_LOG("DB", 240, "Error write to file block-chain : " + written + " <> " + BufWrite.length) return false; } FileItem.size += TrDataLen Block.TrCount = arrTr.length Block.TrDataLen = TrDataLen return true; } CheckSeqHashDB(Block, StrError): any { //defiend in block-loader.ts(CBlock) } WriteBlockHeaderDB(Block, bPreSave?) { if (!bPreSave && Block.BlockNum > this.BlockNumDBMin + global.BLOCK_PROCESSING_LENGTH2) { if (global.USE_CHECK_SAVE_DB) if (!this.CheckSeqHashDB(Block, "WriteBlockHeaderDB")) return false; this.WriteBlockHeader100(Block) this.TruncateBlockDBInner(Block) this.BlockNumDB = Block.BlockNum - 1 var PrevBlock = this.ReadBlockHeaderDB(Block.BlockNum - 1); if (!PrevBlock) { global.ToLogTrace("Cant write header block:" + Block.BlockNum + " prev block not found") throw "ERR: PREV BLOCK NOT FOUND"; return false; } Block.SumHash = global.shaarr2(PrevBlock.SumHash, Block.Hash) Block.SumPow = PrevBlock.SumPow + global.GetPowPower(Block.PowHash) } if (global.DB_VERSION === 2) { return this.WriteBlockHeaderToFile2(Block); } var BufWrite = global.BufLib.GetNewBuffer(global.BLOCK_HEADER_SIZE); this.BlockHeaderToBuf(BufWrite, Block) var Res = this.WriteBufHeaderToFile1(BufWrite, Block.BlockNum); return Res; } WriteBlockHeaderToFile2(Block) { var BufWrite, FileItem, written; var BlockNum = Math.trunc(Block.BlockNum); this.TruncateBufMap(BlockNum) Block.VersionDB = global.DB_VERSION BufWrite = global.BufLib.GetBufferFromObject(Block, FORMAT_STREAM_HEADER, 200, WorkStructStreamHeader) FileItem = global.BlockDB.OpenDBFile(FILE_NAME_BODY, 1) if (!Block.FilePos) { if (!FileItem.size) FileItem.size = 100 Block.FilePos = FileItem.size } written = fs.writeSync(FileItem.fd, BufWrite, 0, BufWrite.length, Block.FilePos) if (written !== BufWrite.length) { global.TO_ERROR_LOG("DB", 242, "Error write to file block-chain : " + written + " <> " + BufWrite.length) return false; } if (Block.FilePos >= FileItem.size) { FileItem.size = Block.FilePos + BufWrite.length } FileItem = global.BlockDB.OpenDBFile(FILE_NAME_HEADER2, 1) var Position = BlockNum * global.BLOCK_HEADER_SIZE2; BufWrite = global.BufLib.GetBufferFromObject(Block, FORMAT_HEADER_VERSION2, global.BLOCK_HEADER_SIZE2, WorkStructHeader2) written = fs.writeSync(FileItem.fd, BufWrite, 0, BufWrite.length, Position) if (Position >= FileItem.size) { FileItem.size = Position + BufWrite.length } if (written !== BufWrite.length) { global.TO_ERROR_LOG("DB", 262, "Error write to file block-header :" + written + " <> " + BufWrite.length) return false; } else { return true; } } WriteBufHeaderToFile1(BufWrite, BlockNum) { BlockNum = Math.trunc(BlockNum) this.TruncateBufMap(BlockNum) var FileItem = global.BlockDB.OpenDBFile(FILE_NAME_HEADER, 1); var Position = BlockNum * global.BLOCK_HEADER_SIZE; var written = fs.writeSync(FileItem.fd, BufWrite, 0, BufWrite.length, Position); if (Position >= FileItem.size) { FileItem.size = Position + BufWrite.length } if (written !== BufWrite.length) { global.TO_ERROR_LOG("DB", 260, "Error write to file block-header :" + written + " <> " + BufWrite.length) return false; } else { return true; } } WriteBlockHeader100(Block) { return; if (Block.BlockNum % 100 !== 0) return; var Hash100; var Num = Block.BlockNum / 100; if (Num <= 0) { Hash100 = [] } else { var PrevHash100 = []; var PrevData = this.DBHeader100.Read(Num - 1); if (PrevData) { PrevHash100 = PrevData.Hash100 } else if (Num > 1) { global.ToLog("NOT FIND PEVHASH100 BlockNum=" + Block.BlockNum, 2) return; } Hash100 = global.sha3arr2(PrevHash100, Block.Hash) } this.DBHeader100.Write({ Num: Num, Hash100: Hash100, Hash: Block.Hash }) } TruncateBlockDBInner100(LastBlock) { return; this.DBHeader100.Truncate(Math.trunc(LastBlock.BlockNum / 100)) } ReadBlockDB(Num) { if (!Num) Num = 0 Num = Math.trunc(Num) var Block = this.ReadBlockHeaderDB(Num); if (Block && Block.TrDataLen) { var Ret = this.ReadBlockBodyDB(Block); if (!Ret) return undefined; } else { if (Block && !global.IsZeroArr(Block.TreeHash)) { global.ToLogTrace("ERROR arrContent on BlockNum=" + Num) return undefined; } } return Block; } ReadBlockBodyDB(Block) { var FileItem = global.BlockDB.OpenDBFile(FILE_NAME_BODY); if (Block.TrDataLen > global.MAX_BLOCK_SIZE * 2) { global.ToLogTrace("Error value TrDataLen, BlockNum=" + Block.BlockNum) return false; } var Position = Block.TrDataPos; var BufRead = global.BufLib.GetNewBuffer(Block.TrDataLen); var bytesRead = fs.readSync(FileItem.fd, BufRead, 0, BufRead.length, Position); if (bytesRead !== BufRead.length) { global.TO_ERROR_LOG("DB", 272, "Error read block-body file: " + FileItem.name + " from POS:" + Position + " bytesRead=" + bytesRead + " of " + BufRead.length + " BlockNum=" + Block.BlockNum) return false; } Block.arrContent = [] Block.arrContentResult = [] var TrCount = BufRead.Read("uint16"); Block.VersionBody = BufRead.Read("uint16") if (TrCount <= global.MAX_TRANSACTION_COUNT) { for (var i = 0; i < TrCount; i++) { var body = BufRead.Read("tr"); if (!body) break; Block.arrContent[i] = body } if (Block.VersionBody === 1) { var Size = TrCount * 6; BufRead.len = Block.TrDataLen - Size for (var i = 0; i < TrCount; i++) { Block.arrContentResult[i] = BufRead.Read("uint") } } } Block.TrCount = Block.arrContent.length return true; } ReadBlockHeaderDB(BlockNum) { if (global.DB_VERSION === 2) { return this.ReadBlockHeaderDB2(BlockNum); } if (BlockNum < 0) { return undefined; } BlockNum = Math.trunc(BlockNum) var Block, BufRead, FileItem, bytesRead, Position; BufRead = global.BufLib.GetNewBuffer(global.BLOCK_HEADER_SIZE) Position = BlockNum * global.BLOCK_HEADER_SIZE var FileItem = global.BlockDB.OpenDBFile(FILE_NAME_HEADER); bytesRead = fs.readSync(FileItem.fd, BufRead, 0, BufRead.length, Position) if (bytesRead !== BufRead.length) return undefined; Block = this.BufToBlockHeader(BufRead, BlockNum) if (Block) { Block.bSave = true Block.Prepared = true } return Block; } ReadBlockHeaderDB2(BlockNum) { var Block, BufRead, FileItem, bytesRead, Position; if (BlockNum < 0) { return undefined; } BlockNum = Math.trunc(BlockNum) Position = BlockNum * global.BLOCK_HEADER_SIZE2 FileItem = global.BlockDB.OpenDBFile(FILE_NAME_HEADER2) BufRead = global.BufLib.GetNewBuffer(global.BLOCK_HEADER_SIZE2) bytesRead = fs.readSync(FileItem.fd, BufRead, 0, BufRead.length, Position) if (bytesRead !== BufRead.length) return undefined; Block = global.BufLib.GetObjectFromBuffer(BufRead, FORMAT_HEADER_VERSION2, WorkStructHeader2) if (!Block.FilePos) { return undefined; } Position = Block.FilePos FileItem = global.BlockDB.OpenDBFile(FILE_NAME_BODY) BufRead = global.BufLib.GetNewBuffer(200) bytesRead = fs.readSync(FileItem.fd, BufRead, 0, BufRead.length, Position) Block = global.BufLib.GetObjectFromBuffer(BufRead, FORMAT_STREAM_HEADER, WorkStructStreamHeader) if (Block.VersionDB !== global.DB_VERSION) { throw (`ERROR Position: ${Position} Block.VersionDB: ${Block.VersionDB}`); } Block.FilePos = Position Block.VersionDB = global.DB_VERSION Block.bSave = true Block.Prepared = true return this.PrepareBlockFields(Block, BlockNum); } ClearBufMap() { this.MapHeader = {} } TruncateBufMap(BlockNum) { if (BlockNum % 10000 === 0) this.ClearBufMap() else { delete this.MapHeader[BlockNum] } } ReadBlockHeaderFromMapDB(BlockNum) { var Block = this.MapHeader[BlockNum]; if (!Block) { Block = this.ReadBlockHeaderDB(BlockNum) this.MapHeader[BlockNum] = Block } else { Block.FromMap = 1 } return Block; } SetTruncateBlockDB(BlockNum) { BlockNum = Math.trunc(BlockNum) if (BlockNum < global.BLOCK_PROCESSING_LENGTH2) BlockNum = global.BLOCK_PROCESSING_LENGTH2 if (this.UseTruncateBlockDB) { if (BlockNum < this.UseTruncateBlockDB) this.UseTruncateBlockDB = BlockNum } else { this.UseTruncateBlockDB = BlockNum } } TruncateBlockDB(LastBlockNum) { this.UseTruncateBlockDB = undefined var Block = this.ReadBlockDB(LastBlockNum); if (!Block) { global.ToLog("************ ERROR TruncateBlockDB - not found block=" + LastBlockNum, 2) return; } this.WriteBlockDB(Block) } TruncateBlockDBInner(LastBlock) { var FItem1, size; if (global.DB_VERSION === 2) { FItem1 = global.BlockDB.OpenDBFile(FILE_NAME_HEADER2, 1) size = (LastBlock.BlockNum + 1) * global.BLOCK_HEADER_SIZE2 } else { FItem1 = global.BlockDB.OpenDBFile(FILE_NAME_HEADER, 1) size = (LastBlock.BlockNum + 1) * global.BLOCK_HEADER_SIZE } if (size < 0) size = 0 if (FItem1.size > size) { FItem1.size = size fs.ftruncateSync(FItem1.fd, FItem1.size) } this.TruncateStat(LastBlock.BlockNum) this.TruncateBlockDBInner100(LastBlock) } ClearDataBase() { if (global.TX_PROCESS && global.TX_PROCESS.RunRPC) global.TX_PROCESS.RunRPC("ClearDataBase", {}) var FItem1 = global.BlockDB.OpenDBFile(FILE_NAME_HEADER, 1); FItem1.size = 0 fs.ftruncateSync(FItem1.fd, FItem1.size) var FItem12 = global.BlockDB.OpenDBFile(FILE_NAME_HEADER2, 1); FItem12.size = 0 fs.ftruncateSync(FItem12.fd, FItem12.size) var FItem2 = global.BlockDB.OpenDBFile(FILE_NAME_BODY, 1); FItem2.size = 0 fs.ftruncateSync(FItem2.fd, FItem2.size) this.DBHeader100.Truncate(- 1) global.DB_VERSION = DEFAULT_DB_VERSION this.BlockNumDB = 0 this.BlockNumDBMin = 0 this.ClearBufMap() this.ClearStat() this.CreateGenesisBlocks() this.StartSyncBlockchain() } CreateGenesisBlocks() { // defiend in block-loader.ts(CBlock) } StartSyncBlockchain(Node?, bSilent?, bCheckPoint?) { // defiend in block-loader.ts(CBlock) } Close() { this.ClearBufMap() this.ReadStateTX() global.BlockDB.CloseDBFile(FILE_NAME_HEADER) global.BlockDB.CloseDBFile(FILE_NAME_HEADER2) global.BlockDB.CloseDBFile(FILE_NAME_BODY) this.DBHeader100.Close() } RewriteAllTransactions() { if (global.TX_PROCESS.Worker) { if (global.TX_PROCESS && global.TX_PROCESS.RunRPC) { global.TX_PROCESS.RunRPC("RewriteAllTransactions", {}) return 1; } } return 0; } BlockHeaderToBuf(BufWrite, Block) { Block.Reserv500 = 0 var len = BufWrite.len; BufWrite.Write(Block.TreeHash, "hash") BufWrite.Write(Block.AddrHash, "hash") BufWrite.Write(Block.PrevHash, "hash") BufWrite.Write(Block.SumHash, "hash") BufWrite.Write(Block.SumPow, "uint") BufWrite.Write(Block.Reserv500, "uint") BufWrite.Write(Block.TrDataPos, "uint") BufWrite.Write(Block.TrDataLen, "uint32") BufWrite.len = len + global.BLOCK_HEADER_SIZE } BufToBlockHeader(BufRead, Num) { var Block: any = {}; var len = BufRead.len; Block.TreeHash = BufRead.Read("hash") Block.AddrHash = BufRead.Read("hash") Block.PrevHash = BufRead.Read("hash") Block.SumHash = BufRead.Read("hash") Block.SumPow = BufRead.Read("uint") Block.Reserv500 = BufRead.Read("uint") Block.TrDataPos = BufRead.Read("uint") Block.TrDataLen = BufRead.Read("uint32") Block.TrCount = 0 BufRead.len = len + global.BLOCK_HEADER_SIZE return this.PrepareBlockFields(Block, Num); } PrepareBlockFields(Block, Num) { Block.AddInfo = global.AddInfoBlock.bind(Block) Block.Info = "" Block.BlockNum = Num Block.SeqHash = this.GetSeqHash(Block.BlockNum, Block.PrevHash, Block.TreeHash) if (Block.BlockNum >= global.BLOCK_PROCESSING_LENGTH2) { global.CalcHashBlockFromSeqAddr(Block) } else { Block.Hash = this.GetHashGenesis(Block.BlockNum) Block.PowHash = Block.Hash } Block.Power = global.GetPowPower(Block.PowHash) if (global.IsZeroArr(Block.Hash)) return undefined; return Block; } GetRows(start, count, Filter, bMinerName) { if (Filter) { Filter = Filter.trim() Filter = Filter.toUpperCase() } var MaxAccount = global.DApps.Accounts.GetMaxAccount(); var WasError = 0; var arr = []; for (var num = start; true; num++) { var Block = this.ReadBlockHeaderDB(num); if (!Block) break; Block.Num = Block.BlockNum if (Block.AddrHash) { Block.Miner = global.ReadUintFromArr(Block.AddrHash, 0) if (Block.BlockNum < 16 || Block.Miner > MaxAccount) Block.Miner = 0 if (bMinerName) { Block.MinerName = "" if (Block.Miner) { var Item = global.DApps.Accounts.ReadState(Block.Miner); if (Item && Item.Name) Block.MinerName = Item.Name.substr(0, 8) } } var Value = global.GetHashFromSeqAddr(Block.SeqHash, Block.AddrHash, Block.BlockNum, Block.PrevHash); Block.Hash1 = Value.Hash1 Block.Hash2 = Value.Hash2 } if (Filter) { var Num = Block.BlockNum; var Bytes = Block.TrDataLen; var Pow = Block.Power; var Miner = Block.Miner; var Date = global.DateFromBlock(Block.BlockNum); try { if (!eval(Filter)) continue; } catch (e) { if (!WasError) global.ToLog(e) WasError = 1 } } arr.push(Block) count-- if (count < 1) break; } return arr; } GetTrRows(BlockNum, start, count) { var arr = []; var Block = this.ReadBlockDB(BlockNum); if (Block && Block.arrContent) for (var num = start; num < start + count; num++) { if (num < 0) continue; if (num >= Block.arrContent.length) break; var Tr: any = { body: Block.arrContent[num] }; this.CheckCreateTransactionObject(Tr, 1) Tr.Num = num Tr.Type = Tr.body[0] Tr.Length = Tr.body.length Tr.Body = [] for (var j = 0; j < Tr.body.length; j++) Tr.Body[j] = Tr.body[j] var App = global.DAppByType[Tr.Type]; if (App) { Tr.Script = App.GetScriptTransaction(Tr.body) if (BlockNum >= this.BlockNumDBMin) Tr.Verify = App.GetVerifyTransaction(Block, BlockNum, Tr.Num, Tr.body) else Tr.Verify = 0 if (Tr.Verify >= 1) { Tr.VerifyHTML = "" if (Tr.Verify > 1) { Tr.VerifyHTML += "(" + Tr.Verify + ")" } } else if (Tr.Verify == - 1) Tr.VerifyHTML = "" else Tr.VerifyHTML = "" } else { Tr.Script = "" Tr.VerifyHTML = "" } arr.push(Tr) } return arr; } ClearStat() { var MAX_ARR_PERIOD = global.MAX_STAT_PERIOD * 2 + 10; this.StatMap = { StartPos: 0, StartBlockNum: 0, Length: 0, "ArrPower": new Float64Array(MAX_ARR_PERIOD), "ArrPowerMy": new Float64Array(MAX_ARR_PERIOD), } } TruncateStat(LastBlockNum) { if (this.StatMap) { var LastNumStat = this.StatMap.StartBlockNum + this.StatMap.Length; var Delta = LastNumStat - LastBlockNum; if (Delta > 0) { this.StatMap.Length -= Delta if (this.StatMap.Length < 0) this.StatMap.Length = 0 } this.StatMap.CaclBlockNum = 0 } } GetStatBlockchainPeriod(Param) { var StartNum = Param.BlockNum; if (!Param.Count || Param.Count < 0) Param.Count = 1000 if (!Param.Miner) Param.Miner = 0 if (!Param.Adviser) Param.Adviser = 0 var Map = {}; var ArrList = new Array(Param.Count); var i = 0; for (var num = StartNum; num < StartNum + Param.Count; num++) { var Power = 0, PowerMy = 0, Nonce = 0; if (num <= this.BlockNumDB) { var Block = this.ReadBlockHeaderDB(num); if (Block) { Power = global.GetPowPower(Block.PowHash) var Miner = global.ReadUintFromArr(Block.AddrHash, 0); Nonce = global.ReadUintFromArr(Block.AddrHash, 6); if (Param.Miner < 0) { if (Param.Adviser) { var Adviser = global.DApps.Accounts.GetAdviserByMiner(Map, Miner); if (Adviser === Param.Adviser) PowerMy = Power } else { PowerMy = Power } } else if (Miner === Param.Miner && !Param.bMinerLess) { PowerMy = Power } else if (Miner <= Param.Miner && Param.bMinerLess) { PowerMy = Power } } } ArrList[i] = PowerMy if (Param.bNonce && PowerMy) ArrList[i] = Nonce i++ } var AvgValue = 0; for (var j = 0; j < ArrList.length; j++) { if (ArrList[j]) AvgValue += ArrList[j] } if (ArrList.length > 0) AvgValue = AvgValue / ArrList.length const MaxSizeArr = 1000; var StepTime = 1; while (ArrList.length >= MaxSizeArr) { if (Param.bNonce) ArrList = global.ResizeArrMax(ArrList) else ArrList = global.ResizeArrAvg(ArrList) StepTime = StepTime * 2 } return { ArrList: ArrList, AvgValue: AvgValue, steptime: StepTime }; } GetStatBlockchain(name, MinLength) { if (!MinLength) return []; var MAX_ARR_PERIOD = global.MAX_STAT_PERIOD * 2 + 10; if (!this.StatMap) { this.ClearStat() } var MaxNumBlockDB = this.GetMaxNumBlockDB(); if (this.StatMap.CaclBlockNum !== MaxNumBlockDB || this.StatMap.CalcMinLength !== MinLength) { this.StatMap.CaclBlockNum = MaxNumBlockDB this.StatMap.CalcMinLength = MinLength var start = MaxNumBlockDB - MinLength + 1; var finish = MaxNumBlockDB + 1; var StartPos = this.StatMap.StartPos; var ArrPower = this.StatMap.ArrPower; var ArrPowerMy = this.StatMap.ArrPowerMy; var StartNumStat = this.StatMap.StartBlockNum; var FinishNumStat = this.StatMap.StartBlockNum + this.StatMap.Length - 1; var CountReadDB = 0; let arr = new Array(MinLength); var arrmy = new Array(MinLength); for (var num = start; num < finish; num++) { var i = num - start; var i2 = (StartPos + i) % MAX_ARR_PERIOD; if (num >= StartNumStat && num <= FinishNumStat && (num < finish - 10)) { arr[i] = ArrPower[i2] arrmy[i] = ArrPowerMy[i2] } else { CountReadDB++ var Power = 0, PowerMy = 0; if (num <= MaxNumBlockDB) { var Block = this.ReadBlockHeaderDB(num); if (Block) { Power = global.GetPowPower(Block.PowHash) var Miner = global.ReadUintFromArr(Block.AddrHash, 0); if (Miner === global.GENERATE_BLOCK_ACCOUNT) { PowerMy = Power } } } arr[i] = Power arrmy[i] = PowerMy ArrPower[i2] = arr[i] ArrPowerMy[i2] = arrmy[i] if (num > FinishNumStat) { this.StatMap.StartBlockNum = num - this.StatMap.Length this.StatMap.Length++ if (this.StatMap.Length > MAX_ARR_PERIOD) { this.StatMap.Length = MAX_ARR_PERIOD this.StatMap.StartBlockNum++ this.StatMap.StartPos++ } } } } this.StatMap["POWER_BLOCKCHAIN"] = arr this.StatMap["POWER_MY_WIN"] = arrmy } var arr = this.StatMap[name]; if (!arr) arr = [] var arrT = this.StatMap["POWER_BLOCKCHAIN"]; for (var i = 0; i < arrT.length; i++) if (!arrT[i]) { this.StatMap = undefined break; } return arr; } GetHashGenesis(Num) { return [Num + 1, 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, Num + 1]; } GetSeqHash(BlockNum, PrevHash, TreeHash) { var arr = [global.GetArrFromValue(BlockNum), PrevHash, TreeHash]; var SeqHash = global.CalcHashFromArray(arr, true); return SeqHash; } CheckCreateTicketObject(Tr, BlockNum?, SetTxID?) { if (!Tr.HashPow && Tr.HashTicket) { Tr.num = BlockNum var FullHashTicket = [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]; for (var i = 0; i < global.TR_TICKET_HASH_LENGTH; i++) FullHashTicket[i] = Tr.HashTicket[i] global.WriteUintToArrOnPos(FullHashTicket, Tr.num, global.TR_TICKET_HASH_LENGTH) Tr.HashPow = global.sha3(FullHashTicket) Tr.power = global.GetPowPower(Tr.HashPow) Tr.TimePow = Tr.power if (SetTxID) Tr.TxID = global.GetHexFromArr(FullHashTicket.slice(0, global.TR_TICKET_HASH_LENGTH + 6)) } } CheckCreateTransactionObject(Tr, SetTxID?, NotPrioritet?) { if (!Tr.HashPow) { var Body = Tr.body; Tr.IsTx = 1 Tr.num = global.ReadUintFromArr(Body, Body.length - 12) if (Tr.num >= global.BLOCKNUM_TICKET_ALGO) Tr.HASH = global.sha3(Body) else Tr.HASH = global.shaarr(Body) Tr.HashTicket = Tr.HASH.slice(0, global.TR_TICKET_HASH_LENGTH) this.CheckCreateTicketObject(Tr, Tr.num, SetTxID) } } BlockChainToBuf(WriteNum, StartNum, EndBlockNum) { if (StartNum === undefined) return global.BufLib.GetNewBuffer(10); var GetLength = EndBlockNum - StartNum + 1; var arr = []; var arr0 = this.PrevBlockChainArr; if (arr0 && arr0.length) { var Block = arr0[arr0.length - 1]; if (Block.BlockNum >= StartNum && Block.BlockNum <= EndBlockNum) { var BlockDB = this.ReadBlockHeaderDB(Block.BlockNum); if (!BlockDB || global.CompareArr(Block.SumHash, BlockDB.SumHash) !== 0) { arr0 = undefined } } } var i0 = 0; for (var num = StartNum; num <= EndBlockNum; num++) { var Block = undefined; if (arr0) { for (var i = i0; i < arr0.length; i++) { i0 = i var Block0 = arr0[i]; if (Block0.BlockNum === num) { Block = Block0 break; } } } if (!Block) Block = this.ReadBlockHeaderDB(num) if (!Block || !Block.Prepared || !Block.Hash) break; arr.push(Block) } this.PrevBlockChainArr = arr return this.ArrHeaderToBuf(WriteNum, arr); } ArrHeaderToBuf(StartNum, arr) { var CountSend = arr.length - global.BLOCK_PROCESSING_LENGTH2; var BufWrite; if (CountSend <= 0) { BufWrite = global.BufLib.GetNewBuffer(10) } else { var BufSize = 6 + 4 + global.BLOCK_PROCESSING_LENGTH2 * 32 + 32 + 6 + CountSend * 64; BufWrite = global.BufLib.GetNewBuffer(BufSize) BufWrite.Write(StartNum, "uint") BufWrite.Write(CountSend, "uint32") for (var i = 0; i < arr.length; i++) { var Block = arr[i]; if (i < global.BLOCK_PROCESSING_LENGTH2) { BufWrite.Write(Block.Hash, "hash") } else { if (i === global.BLOCK_PROCESSING_LENGTH2) { BufWrite.Write(Block.SumHash, "hash") BufWrite.Write(Block.SumPow, "uint") } BufWrite.Write(Block.TreeHash, "hash") BufWrite.Write(Block.AddrHash, "hash") } } } return BufWrite; } }; function AddInfo(Block, Str, BlockNumStart) { if (!global.STAT_MODE) return; if (!Block.Info) Block.Info = Str; else if (Block.Info.length < 2000) { var timesend: any = "" as any + global.SERVER.CurrentBlockNum - BlockNumStart; var now = global.GetCurrentTime(); timesend += ".[" + now.getSeconds().toStringZ(2) + "." + now.getMilliseconds().toStringZ(3) + "]"; Str = timesend + ": " + Str; Block.Info += "\n" + Str; } }; global.AddInfoChain = function(Str) { if (!global.STAT_MODE) return; if (this.BlockNumStart > global.GetCurrentBlockNumByTime() - global.HISTORY_BLOCK_COUNT) AddInfo(this, Str, this.BlockNumStart); }; global.AddInfoBlock = function(Block, Str) { if (!global.STAT_MODE) return; if (Block && Block.BlockNum && Block.BlockNum > global.GetCurrentBlockNumByTime() - global.HISTORY_BLOCK_COUNT) AddInfo(Block, Str, Block.BlockNum); }; global.GetNodeStrPort = function(Node) { if (!Node) return ""; if (global.LOCAL_RUN) return "" + Node.port; else { if (!Node.ip) return ""; var arr = Node.ip.split("."); return "" + arr[2] + "." + arr[3]; } }; declare global { namespace NodeJS { interface Global { //#region block-db.ts BlockDB: DBLib; BLOCK_HEADER_SIZE: number; BLOCK_HEADER_SIZE2: number; DB_VERSION: number; AddInfoChain: Function; AddInfoBlock: Function; GetNodeStrPort: Function; NO_CHECK_BLOCKNUM_ONSTART: number; //#endregion } } }