tera/src/core/transaction-validator.ts

322 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
*/
"use strict";
import { TYPE_TRANSACTION } from '../constant/account';
import * as crypto from 'crypto'
import "../system/dapp"
import "../system/accounts"
import "../system/smart"
import "../system/file"
import "../system/messager"
import "../system/names"
if (global.PROCESS_NAME === "MAIN") {
require("./wallet");
}
import CConsensus from './block-exchange'
import { TeraRBTree, TeraBlock, TeraTr } from '../interfaces/server';
export default class CSmartContract extends CConsensus {
BufHashTree: TeraRBTree<any>
SenderBlockHashMap: { [x: string]: any; }
SenderMap: { [x: string]: any; }
WasReloadSenderMapFromDB: number
constructor(SetKeyPair: crypto.ECDH, RunIP: string, RunPort: number, UseRNDHeader: boolean, bVirtual: boolean) {
super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual)
this.BufHashTree = new TeraRBTree(global.CompareArr)
this.BufHashTree.LastAddNum = 0
this.SenderMap = {}
this.SenderBlockHashMap = {}
if (!global.ADDRLIST_MODE && !this.VirtualMode && global.START_SERVER) {
setInterval(this.ClearOldSenderMapItem.bind(this), 10000)
}
}
AddBlockToHashTree(Block: TeraBlock) {
this.BufHashTree.LastAddNum = Block.BlockNum
var arr = Block.arrContent;
if (arr) {
for (var i = 0; i < arr.length; i++) {
var HASH = global.sha3(arr[i]);
this.BufHashTree.insert(HASH)
}
}
}
DeleteBlockFromHashTree(Block: TeraBlock) {
var arr = Block.arrContent;
if (arr) {
for (var i = 0; i < arr.length; i++) {
var HASH = global.sha3(arr[i]);
this.BufHashTree.remove(HASH)
}
}
}
OnWriteBlock(Block: TeraBlock) {
this.AddToSenderMap(Block)
}
OnDelete(Block: TeraBlock) {
}
BlockProcessTX(Block: TeraBlock) {
if (Block.BlockNum < 1)
return;
var COUNT_MEM_BLOCKS = 0;
var NUM1 = 1240000;
var NUM2 = 1400000;
if (global.LOCAL_RUN) {
NUM1 = 15
NUM2 = 100
}
if (Block.BlockNum > global.BLOCKNUM_TICKET_ALGO) {
NUM1 = 1000000000000
NUM2 = 1000000000000
}
if (Block.BlockNum > NUM1) {
COUNT_MEM_BLOCKS = 1
if (Block.BlockNum > NUM2)
COUNT_MEM_BLOCKS = 60
if (this.BufHashTree.LastAddNum !== Block.BlockNum - 1) {
this.BufHashTree.clear()
for (var num = COUNT_MEM_BLOCKS; num >= 1; num--) {
var Block2 = this.ReadBlockDB(Block.BlockNum - num);
if (Block2) {
this.AddBlockToHashTree(Block2)
}
}
}
}
for (var key in global.DApps) {
global.DApps[key].OnWriteBlockStart(Block)
}
var arrContentResult = [];
var BlockNum = Block.BlockNum;
var arr = Block.arrContent;
if (arr)
for (var i = 0; i < arr.length; i++) {
var HASH = global.sha3(arr[i]);
if (this.BufHashTree.find(HASH)) {
continue;
}
var type = arr[i][0];
var App = global.DAppByType[type];
if (App) {
App.ResultTx = 0
global.DApps.Accounts.BeginTransaction()
var StrHex = global.GetHexFromArr(HASH);
var item;
global.CurTrItem = undefined
if (global.TreeFindTX) {
item = global.TreeFindTX.LoadValue(StrHex)
if (item)
global.CurTrItem = item.TX
}
var Result = App.OnWriteTransaction(Block, arr[i], BlockNum, i);
var SetResult = Result;
if (Result === true) {
if (App.ResultTx)
SetResult = App.ResultTx
if (!global.DApps.Accounts.CommitTransaction(BlockNum, i))
SetResult = 0
}
else {
global.DApps.Accounts.RollBackTransaction()
SetResult = 0
}
if (SetResult === true)
SetResult = 1
arrContentResult[i] = SetResult
if (item) {
var ResultStr = Result;
if (Result === true || typeof Result === "number") {
ResultStr = "Add to blockchain"
if (type === TYPE_TRANSACTION.TYPE_TRANSACTION_FILE)
ResultStr += ": file/" + BlockNum + "/" + i
}
item.cmd = "RetFindTX"
item.ResultStr = "" + ResultStr
item.bFinal = 1
item.Result = SetResult
process.send(item)
}
global.CurTrItem = undefined
}
}
if (COUNT_MEM_BLOCKS) {
var Block2 = this.ReadBlockDB(Block.BlockNum - COUNT_MEM_BLOCKS);
if (Block2)
this.DeleteBlockFromHashTree(Block2)
this.AddBlockToHashTree(Block)
}
if (arrContentResult.length)
process.send({ cmd: "WriteBodyResult", BlockNum: Block.BlockNum, arrContentResult: arrContentResult })
for (var key in global.DApps) {
global.DApps[key].OnWriteBlockFinish(Block)
}
}
BlockDeleteTX(Block: TeraBlock) {
this.BufHashTree.LastAddNum = 0
for (var key in global.DApps) {
global.DApps[key].OnDeleteBlock(Block)
}
}
IsValidTicket(Tr: TeraTr, BlockNum: number) {
this.CheckCreateTicketObject(Tr, BlockNum)
if (Tr.power < global.MIN_POWER_POW_TR)
return - 2;
if (Tr.num !== BlockNum)
return - 3;
return 1;
}
IsValidTransaction(Tr: TeraTr, BlockNum: number) {
if (!Tr.body || Tr.body.length < global.MIN_TRANSACTION_SIZE || Tr.body.length > global.MAX_TRANSACTION_SIZE)
return - 1;
this.CheckCreateTransactionObject(Tr)
if (Tr.power - Math.log2(Tr.body.length / 128) < global.MIN_POWER_POW_TR)
return - 2;
if (Tr.num !== BlockNum)
return - 3;
if (Tr.body[0] === TYPE_TRANSACTION.TYPE_TRANSACTION_ACC_HASH)
return - 4;
return 1;
}
ReWriteDAppTransactions(Length: number) {
if (!global.TX_PROCESS.Worker)
return 0;
if (!Length)
return 0;
var StartNum = this.BlockNumDB - Length + 1;
if (StartNum < 0)
StartNum = 0
var EndNum = this.BlockNumDB;
var MinBlock = global.DApps.Accounts.GetMinBlockAct();
if (MinBlock > StartNum) {
global.ToLog("Cant rewrite transactions. Very long length of the rewriting chain. Max length=" + (this.BlockNumDB - MinBlock))
return 0;
}
if (global.TX_PROCESS && global.TX_PROCESS.RunRPC)
global.TX_PROCESS.RunRPC("ReWriteDAppTransactions", { StartNum: StartNum, EndNum: EndNum })
return 1;
}
AddDAppTransactions(BlockNum: number, Arr: TeraTr[]) {
if (BlockNum % global.PERIOD_ACCOUNT_HASH !== 0)
return;
var BlockNumHash = BlockNum - global.DELTA_BLOCK_ACCOUNT_HASH;
if (BlockNumHash < 0)
return;
var Item = global.DApps.Accounts.GetAccountHashItem(BlockNumHash);
if (Item) {
var Body = [TYPE_TRANSACTION.TYPE_TRANSACTION_ACC_HASH];
global.WriteUintToArr(Body, BlockNumHash)
global.WriteArrToArr(Body, Item.AccHash, 32)
if (BlockNumHash >= global.START_BLOCK_ACCOUNT_HASH3) {
global.WriteUintToArr(Body, Item.AccountMax)
global.WriteArrToArr(Body, Item.SmartHash, 32)
global.WriteUintToArr(Body, Item.SmartCount)
global.WriteUintToArr(Body, BlockNum)
global.WriteUintToArr(Body, 0)
}
var Tr = { body: Body };
this.CheckCreateTransactionObject(Tr)
Arr.unshift(Tr)
}
}
AddTransactionOwn(Tr: TeraTr) {
if (!global.TX_PROCESS.Worker)
return - 6;
var StrHex = global.GetHexFromArr(global.sha3(Tr.body));
global.TX_PROCESS.Worker.send({ cmd: "FindTX", TX: StrHex })
return this.AddTransaction(Tr, true);
}
AddTransaction(Tr: TeraTr, ToAll: boolean) {
// transfer-msg.ts(CMessages)
}
AddToSenderMap(Block: TeraBlock) {
if (!global.START_SERVER)
return;
var BlockNum = Block.BlockNum;
var StrBlockHash = global.GetHexFromArr(Block.Hash);
this.SenderBlockHashMap[BlockNum] = StrBlockHash
var arr = Block.arrContent;
if (arr) {
for (var i = 0; i < arr.length; i++) {
var type = arr[i][0];
var App = global.DAppByType[type];
if (App) {
var Body = arr[i];
var SenderNum = App.GetSenderNum(BlockNum, Body);
if (SenderNum < 0)
continue;
var ItemArr = this.SenderMap[SenderNum];
if (!ItemArr) {
ItemArr = []
this.SenderMap[SenderNum] = ItemArr
}
ItemArr.push({ BlockNum: BlockNum, StrHash: StrBlockHash })
}
}
}
}
GetSenderPrioritet(BlockNum: number, SenderNum: number): number {
if (!this.WasReloadSenderMapFromDB)
this.ReloadSenderMapFromDB()
if (SenderNum < 0)
return global.MAX_LENGTH_SENDER_MAP;
var MaxBlockNum = BlockNum - global.DELTA_START_SENDER_MAP;
if (MaxBlockNum > this.BlockNumDB)
return global.MAX_LENGTH_SENDER_MAP;
var ItemArr = this.SenderMap[SenderNum];
if (!ItemArr) {
return global.MAX_LENGTH_SENDER_MAP;
}
for (var i = ItemArr.length - 1; i--; i >= 0) {
var Item = ItemArr[i];
if (Item.BlockNum <= MaxBlockNum && this.SenderBlockHashMap[Item.BlockNum] === Item.StrHash) {
var Delta = MaxBlockNum - Item.BlockNum;
if (Delta > global.MAX_LENGTH_SENDER_MAP)
Delta = global.MAX_LENGTH_SENDER_MAP
return Delta;
}
}
return global.MAX_LENGTH_SENDER_MAP;
}
ReloadSenderMapFromDB() {
this.SenderMap = {}
this.SenderBlockHashMap = {}
var EndNum = global.GetCurrentBlockNumByTime();
var StartNum = EndNum - global.MAX_LENGTH_SENDER_MAP - global.DELTA_START_SENDER_MAP;
if (StartNum < 0)
StartNum = 0
for (var Num = StartNum; Num < EndNum; Num++) {
var Block = this.ReadBlockDB(Num);
if (!Block)
break;
this.AddToSenderMap(Block)
}
this.WasReloadSenderMapFromDB = 1
}
ClearOldSenderMapItem() {
if (!global.START_SERVER)
return;
var MinBlockNum = global.GetCurrentBlockNumByTime() - (global.MAX_LENGTH_SENDER_MAP + global.COUNT_BLOCKS_FOR_LOAD);
var ArrForDel = [];
for (var key in this.SenderMap) {
var ItemArr = this.SenderMap[key];
while (ItemArr.length) {
var Item = ItemArr[0];
if (Item.BlockNum > MinBlockNum)
break;
ItemArr.shift()
}
if (ItemArr.length === 0)
ArrForDel.push(key)
}
for (var i = 0; i < ArrForDel.length; i++) {
delete this.SenderMap[ArrForDel[i]]
}
}
};