/* * @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://web.telegram.org/#/im?p=@terafoundation */ "use strict"; require("../dapp/dapp"); require("../dapp/accounts"); require("../dapp/smart"); require("../dapp/file"); require("../dapp/messager"); require("../dapp/names"); if(global.PROCESS_NAME === "MAIN" || global.PROCESS_NAME === "TX") require("./wallet"); module.exports = class CSmartContract extends require("./block-exchange") { constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) { super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) this.BufHashTree = new RBTree(CompareArr) this.BufHashTree.LastAddNum = 0 } AddBlockToHashTree(Block) { this.BufHashTree.LastAddNum = Block.BlockNum var arr = Block.arrContent; if(arr) { for(var i = 0; i < arr.length; i++) { var HASH = shaarr(arr[i]); this.BufHashTree.insert(HASH) } } } DeleteBlockFromHashTree(Block) { var arr = Block.arrContent; if(arr) { for(var i = 0; i < arr.length; i++) { var HASH = shaarr(arr[i]); this.BufHashTree.remove(HASH) } } } OnWriteBlock(Block) { } BlockProcessTX(Block) { 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 DApps) { 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 = shaarr(arr[i]); if(this.BufHashTree.find(HASH)) { continue; } var type = arr[i][0]; var App = DAppByType[type]; if(App) { App.ResultTx = 0 DApps.Accounts.BeginTransaction() var StrHex = GetHexFromArr(sha3(arr[i])); var item = global.TreeFindTX.LoadValue(StrHex); if(item) global.CurTrItem = item.TX else global.CurTrItem = undefined var Result = App.OnWriteTransaction(Block, arr[i], BlockNum, i); var SetResult = Result; if(Result === true) { if(App.ResultTx) SetResult = App.ResultTx if(!DApps.Accounts.CommitTransaction(BlockNum, i)) SetResult = 0 } else { 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 === global.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 DApps) { DApps[key].OnWriteBlockFinish(Block) } } BlockDeleteTX(Block) { this.BufHashTree.LastAddNum = 0 for(var key in DApps) { DApps[key].OnDeleteBlock(Block) } } OnDelete(Block) { } IsValidTicket(Tr, BlockNum) { this.CheckCreateTicketObject(Tr, BlockNum) if(Tr.power < MIN_POWER_POW_TR) return - 2; if(Tr.num !== BlockNum) return - 3; return 1; } IsValidTransaction(Tr, BlockNum) { if(!Tr.body || Tr.body.length < MIN_TRANSACTION_SIZE || Tr.body.length > MAX_TRANSACTION_SIZE) return - 1; this.CheckCreateTransactionObject(Tr) if(Tr.power - Math.log2(Tr.body.length / 128) < MIN_POWER_POW_TR) return - 2; if(Tr.num !== BlockNum) return - 3; if(Tr.body[0] === TYPE_TRANSACTION_ACC_HASH) return - 4; return 1; } ReWriteDAppTransactions(Length) { if(!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 = DApps.Accounts.GetMinBlockAct(); if(MinBlock > StartNum) { 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, Arr) { if(BlockNum % PERIOD_ACCOUNT_HASH !== 0) return ; var BlockNumHash = BlockNum - DELTA_BLOCK_ACCOUNT_HASH; if(BlockNumHash < 0) return ; var Item = DApps.Accounts.GetAccountHashItem(BlockNumHash); if(Item) { var Body = [TYPE_TRANSACTION_ACC_HASH]; WriteUintToArr(Body, BlockNumHash) WriteArrToArr(Body, Item.AccHash, 32) if(BlockNumHash >= START_BLOCK_ACCOUNT_HASH3) { WriteUintToArr(Body, Item.AccountMax) WriteArrToArr(Body, Item.SmartHash, 32) WriteUintToArr(Body, Item.SmartCount) WriteUintToArr(Body, BlockNum) WriteUintToArr(Body, 0) } var Tr = {body:Body}; this.CheckCreateTransactionObject(Tr) Arr.unshift(Tr) } } AddTransactionOwn(Tr) { if(!global.TX_PROCESS.Worker) return - 6; var StrHex = GetHexFromArr(sha3(Tr.body)); global.TX_PROCESS.Worker.send({cmd:"FindTX", TX:StrHex}) return this.AddTransaction(Tr, 1); } };