tera/src/process/tx-process.ts

369 lines
12 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
*/
global.PROCESS_NAME = "TX";
import * as crypto from 'crypto';
import "../core/constant"
global.DATA_PATH = global.GetNormalPathString(global.DATA_PATH);
global.CODE_PATH = global.GetNormalPathString(global.CODE_PATH);
import "../core/library"
global.READ_ONLY_DB = 0;
var LastAlive = Date.now();
setTimeout(function() {
setInterval(CheckAlive, 1000);
}, 20000);
setInterval(global.PrepareStatEverySecond, 1000);
if (process.send) {
setInterval(function() {
process.send({ cmd: "Alive" });
}, 1000);
process.send({ cmd: "online", message: "OK" });
global.ToLogClient = function(Str, StrKey, bFinal) {
process.send({
cmd: "ToLogClient",
Str: "" + Str,
StrKey: StrKey,
bFinal: bFinal
});
};
}
process.on('message', function(msg) {
LastAlive = Date.now();
switch (msg.cmd) {
case "ALive":
break;
case "Exit":
process.exit(0);
break;
case "call":
var Err = 0;
var Ret;
try {
Ret = global[msg.Name](msg.Params);
} catch (e) {
Err = 1;
Ret = "" + e;
}
if (msg.id)
process.send({
cmd: "retcall",
id: msg.id,
Err: Err,
Params: Ret
});
break;
case "FindTX":
global.TreeFindTX.SaveValue(msg.TX, msg);
break;
case "SetSmartEvent":
global.TreeFindTX.SaveValue("Smart:" + msg.Smart, 1);
break;
case "Eval":
global.EvalCode(msg.Code);
break;
default:
break;
}
});
global.SetStatMode = function(Val) {
global.STAT_MODE = Val;
return global.STAT_MODE;
};
function CheckAlive() {
if (global.NOALIVE)
return;
var Delta = Date.now() - LastAlive;
if (Delta > 100 * 1000) {
global.ToLog("TX-PROCESS: ALIVE TIMEOUT Stop and exit: " + Delta);
process.exit(0);
return;
}
};
process.on('uncaughtException', function(err) {
global.ToError(err.stack);
global.ToLog(err.stack);
global.TO_ERROR_LOG("TX-PROCESS", 777, err);
global.ToLog("-----------------TX-PROCESS EXIT------------------");
process.exit();
});
process.on('error' as any, function(err: TeraError) {
global.ToError("TX-PROCESS:\n" + err.stack);
global.ToLog(err.stack);
});
global.HTTP_PORT_NUMBER = 0;
import CServerDB from '../core/transaction-validator'
import { STreeBuffer } from '../core/base';
import { DB_FORMAT } from '../constant/db-format';
var KeyPair = crypto.createECDH('secp256k1');
KeyPair.setPrivateKey(Buffer.from([77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77]));
global.SERVER = new CServerDB(KeyPair, undefined, undefined, false, true);
global.TreeFindTX = new STreeBuffer(30 * 1000, global.CompareItemHashSimple, "string");
setInterval(function() {
if (global.SERVER) {
global.SERVER.Close();
}
DoTXProcess();
}, 10);
var BlockTree = new STreeBuffer(30 * 1000, global.CompareItemHashSimple, "number");
global.bShowDetail = 0;
var StopTxProcess = 0;
var MinimalValidBlock = 0;
var LastBlockNum = undefined;
function DoTXProcess() {
if (StopTxProcess)
return;
if (LastBlockNum === undefined)
InitTXProcess();
var BlockMin = FindMinimal();
if (!BlockMin) {
if (global.bShowDetail)
global.ToLog("!BlockMin");
return;
}
var StartTime = Date.now();
if (global.bShowDetail)
global.ToLog("BlockMin: " + BlockMin.BlockNum + " LastBlockNum=" + LastBlockNum);
var CountTX = 0;
for (var Num = BlockMin.BlockNum; Num < BlockMin.BlockNum + 200; Num++) {
var EndTime = Date.now();
var Delta = EndTime - StartTime;
if (Delta >= 1000)
break;
var Block = global.SERVER.ReadBlockDB(Num);
if (!Block) {
if (global.bShowDetail)
global.ToLog("!Block");
break;
}
if (!IsValidSumHash(Block)) {
break;
}
var Item = BlockTree.LoadValue(Block.BlockNum, 1);
if (Item && global.CompareArr(Item.SumHash, Block.SumHash) === 0) {
if (global.bShowDetail)
global.ToLog("WAS CALC: " + Num + " SumHash: " + global.GetHexFromArr(Block.SumHash).substr(0, 12));
continue;
}
if (Num > 0) {
var Block0 = global.SERVER.ReadBlockDB(Num - 1);
if (Block0) {
var Item0 = BlockTree.LoadValue(Block0.BlockNum, 1);
if (Item0 && global.CompareArr(Item0.SumHash, Block0.SumHash) !== 0) {
break;
}
}
}
global.SERVER.BlockProcessTX(Block);
if (Num % 100000 === 0)
global.ToLog("CALC: " + Num);
CountTX++;
if (global.bShowDetail)
global.ToLog(" CALC: " + Num + " SumHash: " + global.GetHexFromArr(Block.SumHash).substr(0, 12));
BlockTree.SaveValue(Block.BlockNum, { BlockNum: Block.BlockNum, SumHash: Block.SumHash });
LastBlockNum = Block.BlockNum;
}
};
function FindMinimal() {
var MaxNumBlockDB = global.SERVER.GetMaxNumBlockDB();
if (MaxNumBlockDB && MaxNumBlockDB < LastBlockNum) {
if (global.bShowDetail)
global.ToLog("MaxNumBlockDB<LastBlockNum: " + MaxNumBlockDB + "<" + LastBlockNum);
LastBlockNum = MaxNumBlockDB - 1;
BlockTree.Clear();
}
if (LastBlockNum < MinimalValidBlock)
LastBlockNum = MinimalValidBlock;
if (global.bShowDetail)
global.ToLog("FindMinimal from LastBlockNum=" + LastBlockNum);
for (var Num = LastBlockNum; Num--; Num >= 0) {
if (Num < MinimalValidBlock)
break;
var Block = global.SERVER.ReadBlockHeaderDB(Num);
if (!Block) {
continue;
}
if (!IsValidSumHash(Block)) {
continue;
}
if (Block.BlockNum % global.PERIOD_ACCOUNT_HASH === 0) {
var Item = global.DApps.Accounts.GetAccountHashItem(Block.BlockNum);
if (Item) {
BlockTree.SaveValue(Block.BlockNum, Item);
}
}
var Item = BlockTree.LoadValue(Block.BlockNum, 1);
if (Item && global.CompareArr(Item.SumHash, Block.SumHash) === 0)
return Block;
if (global.bShowDetail)
global.ToLog("" + Num + " " + Block.BlockNum + ". Item=" + JSON.stringify(Item) + " MinimalValidBlock=" + MinimalValidBlock);
}
if (global.bShowDetail)
global.ToLog("MinimalValidBlock:" + MinimalValidBlock);
if (MinimalValidBlock === 0 && LastBlockNum > 0) {
RewriteAllTransactions();
}
Block = global.SERVER.ReadBlockHeaderDB(MinimalValidBlock);
return Block;
};
function IsValidSumHash(Block) {
if (Block.BlockNum <= MinimalValidBlock + global.BLOCK_PROCESSING_LENGTH2)
return 1;
if (Block.BlockNum < 16)
return 1;
if (global.IsZeroArr(Block.SumHash))
return 0;
var PrevBlock = global.SERVER.ReadBlockHeaderDB(Block.BlockNum - 1);
if (!PrevBlock)
return 0;
var SumHash2 = global.shaarr2(PrevBlock.SumHash, Block.Hash);
if (global.CompareArr(SumHash2, Block.SumHash) === 0)
return 1;
return 0;
};
function InitTXProcess() {
var StateTX = global.DApps.Accounts.DBStateTX.Read(0);
if (!StateTX) {
LastBlockNum = 0;
var MaxNum = global.DApps.Accounts.DBAccountsHash.GetMaxNum();
if (MaxNum > 0) {
var Item = global.DApps.Accounts.DBAccountsHash.Read(MaxNum);
if (Item) {
LastBlockNum = Item.BlockNum;
}
}
global.ToLog("DETECT NEW VER on BlockNum=" + LastBlockNum, 2);
global.DApps.Accounts.DBStateTX.Write({
Num: 0,
BlockNum: LastBlockNum,
BlockNumMin: MinimalValidBlock
});
}
StateTX = global.DApps.Accounts.DBStateTX.Read(0);
LastBlockNum = StateTX.BlockNum;
MinimalValidBlock = StateTX.BlockNumMin;
LastBlockNum = global.PERIOD_ACCOUNT_HASH * Math.trunc(LastBlockNum / global.PERIOD_ACCOUNT_HASH);
if (LastBlockNum > 100) {
LastBlockNum = 1 + LastBlockNum - 100;
}
global.ToLog("Start CalcMerkleTree", 2);
global.DApps.Accounts.CalcMerkleTree(1);
global.ToLog("Finsih CalcMerkleTree", 2);
if (LastBlockNum <= 0)
RewriteAllTransactions();
else
global.ToLog("Start NUM = " + LastBlockNum, 2);
};
global.ClearDataBase = ClearDataBase;
function ClearDataBase() {
MinimalValidBlock = 0;
for (var key in global.DApps) {
global.DApps[key].ClearDataBase();
}
LastBlockNum = 0;
BlockTree.Clear();
};
global.RewriteAllTransactions = RewriteAllTransactions;
function RewriteAllTransactions() {
if (MinimalValidBlock > 0) {
global.ToLog("*************Cant run RewriteAllTransactions, MinimalValidBlock:" + MinimalValidBlock, 2);
return;
}
global.ToLog("*************RewriteAllTransactions");
for (var key in global.DApps) {
global.DApps[key].ClearDataBase();
}
LastBlockNum = 0;
BlockTree.Clear();
global.ToLog("Start num = " + LastBlockNum, 2);
};
global.ReWriteDAppTransactions = ReWriteDAppTransactions;
function ReWriteDAppTransactions(Params) {
var StartNum = Params.StartNum;
var EndNum = Params.EndNum;
global.ToLog("ReWriteDAppTransactions: " + StartNum + " - " + EndNum);
BlockTree.Clear();
if (StartNum < LastBlockNum)
LastBlockNum = StartNum;
global.ToLog("Start num = " + LastBlockNum, 2);
};
function TXPrepareLoadRest(BlockNum) {
StopTxProcess = 1;
MinimalValidBlock = BlockNum;
global.ToLog("*************TXPrepareLoadRest:" + BlockNum, 2);
for (var key in global.DApps) {
global.DApps[key].ClearDataBase();
}
LastBlockNum = BlockNum;
BlockTree.Clear();
global.DApps.Accounts.DBStateTX.Write({ Num: 0, BlockNum: LastBlockNum, BlockNumMin: LastBlockNum });
};
global.TXPrepareLoadRest = TXPrepareLoadRest;
function TXWriteAccArr(Params) {
var WorkStruct = {};
var WorkFormat = global.DApps.Accounts.FORMAT_ACCOUNT_ROW;
global.ToLog("Write accounts: " + Params.StartNum + "-" + Params.Arr.length, 2);
for (var i = 0; i < Params.Arr.length; i++) {
var Data = global.BufLib.GetObjectFromBuffer(Params.Arr[i], WorkFormat, WorkStruct);
Data.Num = Params.StartNum + i;
global.DApps.Accounts._DBStateWrite(Data, MinimalValidBlock);
}
};
global.TXWriteAccArr = TXWriteAccArr;
function TXWriteSmartArr(Params) {
var WorkStruct = {};
var WorkFormat = DB_FORMAT.FORMAT_SMART_ROW;
global.ToLog("Write smarts: " + Params.StartNum + "-" + Params.Arr.length, 2);
for (var i = 0; i < Params.Arr.length; i++) {
var Data = global.BufLib.GetObjectFromBuffer(Params.Arr[i], WorkFormat, WorkStruct);
Data.Num = Params.StartNum + i;
global.DApps.Smart.DBSmart.Write(Data);
}
};
global.TXWriteSmartArr = TXWriteSmartArr;
function TXWriteAccHash() {
StopTxProcess = 0;
global.ToLog("Start TXWriteAccHash: " + MinimalValidBlock, 2);
for (var num = 0; true; num++) {
var Item = global.DApps.Smart.DBSmart.Read(num);
if (!Item)
break;
var Body = global.BufLib.GetBufferFromObject(Item, DB_FORMAT.FORMAT_SMART_ROW, 20000, {});
global.DApps.Smart.DBSmartWrite(Item);
}
global.DApps.Accounts.CalcMerkleTree(1);
var Block = { BlockNum: MinimalValidBlock, SumHash: [] };
var MaxAccount = global.DApps.Accounts.GetMaxAccount();
var DataHash = global.DApps.Accounts.CalcHash(Block, MaxAccount);
return DataHash;
};
global.TXWriteAccHash = TXWriteAccHash;
global.EvalCode = function(Code) {
var Result;
try {
var ret = eval(Code);
Result = JSON.stringify(ret, undefined, 4);
} catch (e) {
Result = "" + e;
}
return Result;
};