tera/src/system/accounts.ts

1412 lines
53 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 DBRow from '../core/db/db-row'
import '../core/rest_tables'
import { secp256k1 } from '../core/library'
import { TYPE_TRANSACTION } from '../constant/account'
const MAX_SUM_TER = 1e9;
const MAX_SUM_CENT = 1e9;
import DBLib from "../core/db/db"
global.HistoryDB = new DBLib();
const FILE_NAME_HISTORY = "history-body";
var WorkStructHistory = {};
const BLOCK_CREATE_INTERVAL = 10;
global.TYPE_TRANSACTION_CREATE = 100;
const TYPE_DEPRECATED_TRANSFER1 = 105;
const TYPE_DEPRECATED_TRANSFER2 = 110;
const TYPE_TRANSACTION_TRANSFER = 111;
global.TYPE_TRANSACTION_ACC_HASH = 119;
global.FORMAT_CREATE = "{\
Type:byte,\
Currency:uint,\
PubKey:arr33,\
Name:str40,\
Adviser:uint,\
Smart:uint32,\
Reserve:arr3,\
}";
global.FORMAT_MONEY_TRANSFER = '{\
Type:byte,\
Currency:uint,\
FromID:uint,\
To:[{ID:uint,SumCOIN:uint,SumCENT:uint32}],\
Description:str,\
OperationID:uint,\
Sign:arr64,\
}';
const WorkStructTransfer = {};
global.FORMAT_MONEY_TRANSFER_BODY = global.FORMAT_MONEY_TRANSFER.replace("Sign:arr64,", "");
global.FORMAT_MONEY_TRANSFER2 = "{\
Type:byte,\
Version:byte,\
Currency:uint,\
FromID:uint,\
To:[{ID:uint,SumCOIN:uint,SumCENT:uint32}],\
Description:str,\
OperationID:uint,\
Sign:arr64,\
}";
const WorkStructTransfer2 = {};
global.FORMAT_MONEY_TRANSFER_BODY2 = global.FORMAT_MONEY_TRANSFER2.replace("Sign:arr64,", "");
global.FORMAT_MONEY_TRANSFER3 = "{\
Type:byte,\
Version:byte,\
Reserve:uint,\
FromID:uint,\
To:[{PubKey:tr,ID:uint,SumCOIN:uint,SumCENT:uint32}],\
Description:str,\
OperationID:uint,\
Body:tr,\
Sign:arr64,\
}";
const WorkStructTransfer3 = {};
global.FORMAT_MONEY_TRANSFER_BODY3 = global.FORMAT_MONEY_TRANSFER3.replace("Sign:arr64,", "");
global.FORMAT_ACCOUNT_HASH = "{\
Type:byte,\
BlockNum:uint,\
AccHash:buffer32,\
}";
global.FORMAT_ACCOUNT_HASH3 = "{\
Type:byte,\
BlockNum:uint,\
AccHash:buffer32,\
AccountMax:uint,\
SmartHash:buffer32,\
SmartCount:uint,\
}";
import DApp from './dapp'
class MerkleDBRow extends DBRow {
private MerkleTree
private MerkleArr
private MerkleCalc
constructor(FileName, DataSize, Format, bReadOnly) {
super(FileName, DataSize, Format, bReadOnly)
this.InitMerkleTree()
}
InitMerkleTree() {
this.MerkleTree = undefined
this.MerkleArr = []
this.MerkleCalc = {}
}
CalcMerkleTree(bForceUpdate) {
if (!this.MerkleTree || bForceUpdate) {
this.MerkleCalc = {}
this.MerkleTree = { LevelsHash: [this.MerkleArr], RecalcCount: 0 }
var GetMaxNum = this.GetMaxNum();
for (var num = 0; num <= GetMaxNum; num++) {
var Buf = this.Read(num, 1);
if (!Buf) {
if (global.WATCHDOG_DEV)
global.ToErrorTx("CalcMerkleTree: Break account reading on num: " + num)
break;
}
this.MerkleArr[num] = global.shaarr(Buf)
this.MerkleCalc[num] = 1
}
}
this.MerkleTree.RecalcCount = 0
global.UpdateMerklTree(this.MerkleTree, this.MerkleCalc, 0)
this.MerkleCalc = {}
return this.MerkleTree.Root;
}
Write(Data) {
var RetBuf: any = {};
var bRes = DBRow.prototype.Write.call(this, Data, RetBuf);
if (bRes) {
var Hash = global.shaarr(RetBuf.Buf);
this.MerkleArr[Data.Num] = Hash
this.MerkleCalc[Data.Num] = 1
}
return bRes;
}
Truncate(LastNum) {
DBRow.prototype.Truncate.call(this, LastNum)
if (this.MerkleArr.length !== LastNum + 1) {
this.MerkleArr.length = LastNum + 1
this.MerkleCalc[LastNum] = 1
}
}
};
export default class AccountApp extends DApp {
CreateTrCount
FORMAT_ACCOUNT_ROW
SIZE_ACCOUNT_ROW
DBState
FORMAT_ACCOUNT_ROW_REST
SIZE_ACCOUNT_ROW_REST
DBRest
DBAct
DBActPrev
FORMAT_STATE_HISTORY
DBStateHistory
HistoryFormatArr
DBStateTX: DBRow
DBAccountsHash
WasCheckRestDB
ResultTx
DBChanges
constructor() {
super()
var bReadOnly = (global.PROCESS_NAME !== "TX");
this.CreateTrCount = 0
this.FORMAT_ACCOUNT_ROW = "{\
Currency:uint,\
PubKey:arr33,\
Name:str40,\
Value:{SumCOIN:uint,SumCENT:uint32, OperationID:uint,Smart:uint32,Data:arr80},\
BlockNumCreate:uint,\
Adviser:uint,\
Reserve:arr9,\
}"
this.SIZE_ACCOUNT_ROW = 6 + 33 + 40 + (6 + 4 + 6 + 84) + 6 + 6 + 9
this.DBState = new MerkleDBRow("accounts-state", this.SIZE_ACCOUNT_ROW, this.FORMAT_ACCOUNT_ROW, bReadOnly)
this.FORMAT_ACCOUNT_ROW_REST = "{\
Arr:[{\
BlockNum:uint,\
Value:{SumCOIN:uint,SumCENT:uint32, OperationID:uint,Smart:uint32,Data:arr80,Reserv:arr96},\
}],\
Reserv0:arr10,\
}"
this.SIZE_ACCOUNT_ROW_REST = 1024
this.DBRest = new DBRow("accounts-rest", this.SIZE_ACCOUNT_ROW_REST, this.FORMAT_ACCOUNT_ROW_REST, bReadOnly)
this.DBAct = new DBRow("accounts-act", 6 + 6 + (6 + 4 + 6 + 6 + 84) + 1 + 11, "{ID:uint, BlockNum:uint,PrevValue:{SumCOIN:uint,SumCENT:uint32, NextPos:uint, OperationID:uint,Smart:uint32,Data:arr80}, Mode:byte, TrNum:uint16, Reserve: arr9}", bReadOnly)
this.DBActPrev = new DBRow("accounts-act-prev", this.DBAct.DataSize, this.DBAct.Format, bReadOnly)
this.FORMAT_STATE_HISTORY = "{NextPos:uint,Reserv:arr2}"
this.DBStateHistory = new DBRow("history-state", 8, this.FORMAT_STATE_HISTORY, bReadOnly)
global.HistoryDB.OpenDBFile(FILE_NAME_HISTORY, !bReadOnly)
this.HistoryFormatArr = ["{Type:byte, BlockNum:uint32,TrNum:uint16, NextPos:uint}", "{Type:byte, BlockNum:uint32,TrNum:uint16, NextPos:uint, Direct:str1,CorrID:uint, SumCOIN:uint,SumCENT:uint32}"]
this.DBStateTX = new DBRow("accounts-tx", 6 + 6 + 88, "{BlockNum:uint, BlockNumMin:uint, Reserve: arr88}", bReadOnly)
if (global.READ_ONLY_DB)
return;
this.DBAccountsHash = new DBRow("accounts-hash3", 6 + 32 + 32 + 32 + 6 + 6 + 14, "{BlockNum:uint, AccHash:hash, SumHash:hash, SmartHash:hash, AccountMax:uint, SmartCount:uint, Reserve: arr14}", bReadOnly)
if (global.START_SERVER)
return;
if (!bReadOnly)
this.Start()
setInterval(this.ControlActSize.bind(this), 60 * 1000)
}
Start(bClean?) {
if (global.LOCAL_RUN)
bClean = 1
if (!bClean && this.DBState.GetMaxNum() + 1 >= global.BLOCK_PROCESSING_LENGTH2)
return;
this.DBState.MerkleTree = undefined
this.DBState.Truncate(- 1)
this.DBStateHistory.Truncate(- 1)
this.DBAct.Truncate(- 1)
this.DBActPrev.Truncate(- 1)
this.DBAccountsHash.Truncate(- 1)
this.DBStateTX.Truncate(- 1)
this.DBRest.Truncate(- 1)
this._DBStateWrite({ Num: 0, PubKey: [], Value: { BlockNum: 1, SumCOIN: 0.95 * global.TOTAL_SUPPLY_TERA }, Name: "System account" }, 1)
for (var i = 1; i < 8; i++) {
this._DBStateWrite({ Num: i, PubKey: [], Value: { BlockNum: 1 }, Name: "" })
}
this._DBStateWrite({ Num: 8, PubKey: global.GetArrFromHex(global.ARR_PUB_KEY[0]), Value: { BlockNum: 1, SumCOIN: 0.05 * global.TOTAL_SUPPLY_TERA }, Name: "Founder account" })
this._DBStateWrite({ Num: 9, PubKey: global.GetArrFromHex(global.ARR_PUB_KEY[1]), Value: { BlockNum: 1, SumCOIN: 0 }, Name: "Developer account" })
for (var i = 10; i < global.BLOCK_PROCESSING_LENGTH2; i++)
this._DBStateWrite({ Num: i, PubKey: global.GetArrFromHex(global.ARR_PUB_KEY[i - 8]), Value: { BlockNum: 1 }, Name: "" })
this.DBStateTX.Write({ Num: 0, BlockNum: 0 })
this.CalcMerkleTree(1)
var FileItem = global.HistoryDB.OpenDBFile(FILE_NAME_HISTORY, 1);
fs.ftruncateSync(FileItem.fd, 0)
global.ToLog("MAX_NUM:" + this.DBState.GetMaxNum())
}
Close() {
this.DBState.Close()
this.DBActPrev.Close()
this.DBAct.Close()
if (this.DBAccountsHash)
this.DBAccountsHash.Close()
if (this.DBStateTX)
this.DBStateTX.Close()
this.DBRest.Close()
if (this.DBStateHistory)
this.DBStateHistory.Close()
}
ClearDataBase() {
this.Start(1)
}
CheckRestDB() {
if (!global.SERVER)
return;
if (this.WasCheckRestDB)
return;
this.WasCheckRestDB = 1
var MaxNumBlock = global.SERVER.GetMaxNumBlockDB();
if (this.DBState.GetMaxNum() >= 0 && this.DBRest.GetMaxNum() < 0 && MaxNumBlock > 0) {
this.FillRestDB(MaxNumBlock)
}
}
FillRestDB(BlockNum) {
global.ToLog("******************************START FillRestDB")
var Max = this.DBState.GetMaxNum();
for (var Num = 0; Num <= Max; Num++) {
var Data = this.DBState.Read(Num);
var RestData = this.ReadRest(Num);
if (Num % 10000 === 0)
global.ToLog("Fill Rest DB : " + Num)
RestData.Arr[0] = { BlockNum: BlockNum, Value: Data.Value }
this.DBRest.Write(RestData)
}
global.ToLog("******************************FINISH FillRestDB")
}
_DBStateWrite(Data?, BlockNum?, b?) {
this.CheckRestDB()
this.DBState.Write(Data)
if (Data.Num === undefined)
throw "Error undefined Num DBRest !!";
var RestData = this.ReadRest(Data.Num);
DoRest(RestData, Data, BlockNum)
this.DBRest.Write(RestData)
}
_DBStateTruncate(Num) {
this.DBState.Truncate(Num)
this.DBRest.Truncate(Num)
}
ReadRest(Num) {
var COUNT_STATE = 5;
var RestData = this.DBRest.Read(Num);
if (!RestData || RestData.Arr.length !== COUNT_STATE) {
RestData = { Num: Num, Arr: [] }
for (var i = 0; i < COUNT_STATE; i++)
RestData.Arr[i] = { BlockNum: 0, Value: {} }
}
if (RestData.Arr.length !== COUNT_STATE)
throw "Error RestData.Arr.length = (" + RestData.Arr.length + ")";
return RestData;
}
ControlActSize() {
var MaxNum = this.DBAct.GetMaxNum();
if (MaxNum >= global.TRANSACTION_PROOF_COUNT * 2) {
global.ToLog("Rename act files")
this.DBActPrev.CloseDBFile(this.DBActPrev.FileName)
this.DBAct.CloseDBFile(this.DBAct.FileName)
if (fs.existsSync(this.DBActPrev.FileNameFull)) {
var FileNameFull2 = this.DBActPrev.FileNameFull + "_del";
try {
fs.renameSync(this.DBActPrev.FileNameFull, FileNameFull2)
} catch (e) {
global.ToErrorTx("Can-t rename for delete act-file: " + FileNameFull2 + " " + e)
return;
}
fs.unlinkSync(FileNameFull2)
}
try {
fs.renameSync(this.DBAct.FileNameFull, this.DBActPrev.FileNameFull)
} catch (e) {
global.ToErrorTx("Can-t rename act-file!" + e)
return;
}
}
}
GetSenderNum(BlockNum, Body) {
var Type = Body[0];
if (Type && Body.length > 90) {
switch (Type) {
case TYPE_TRANSACTION.TYPE_TRANSACTION_CREATE:
{
if (BlockNum % BLOCK_CREATE_INTERVAL !== 0)
return 0;
var Num = BlockNum;
return Num;
}
case TYPE_TRANSACTION_TRANSFER:
var Num = global.ReadUintFromArr(Body, 1 + 1 + 6);
return Num;
case TYPE_TRANSACTION.TYPE_TRANSACTION_ACC_HASH:
return - 1;
}
}
return 0;
}
OnDeleteBlock(Block) {
if (Block.BlockNum < 1)
return;
this.DeleteAct(Block.BlockNum)
}
OnWriteBlockStart(Block) {
this.CreateTrCount = 0
if (Block.BlockNum < 1)
return;
this.OnDeleteBlock(Block)
this.BeginBlock()
}
OnWriteBlockFinish(Block) {
try {
this.BeginTransaction()
this.DoCoinBaseTR(Block)
this.CommitTransaction(Block.BlockNum, 0xFFFF)
} catch (e) {
this.RollBackTransaction()
global.ToErrorTx("BlockNum:" + Block.BlockNum + " - DoCoinBaseTR: " + e)
}
this.CommitBlock(Block)
}
OnWriteTransaction(Block, Body, BlockNum, TrNum, ContextFrom) {
var Result;
try {
Result = this.OnWriteTransactionTR(Block, Body, BlockNum, TrNum, ContextFrom)
} catch (e) {
Result = "" + e
if (global.WATCHDOG_DEV)
global.ToErrorTx("BlockNum:" + BlockNum + ":" + e)
}
if (Result !== true) {
this.RollBackTransaction()
}
return Result;
}
OnWriteTransactionTR(Block, Body, BlockNum, TrNum, ContextFrom) {
var Type = Body[0];
var Result;
switch (Type) {
case TYPE_TRANSACTION.TYPE_TRANSACTION_CREATE:
{
Result = this.TRCreateAccount(Body, BlockNum, TrNum, ContextFrom)
break;
}
case TYPE_DEPRECATED_TRANSFER1:
{
Result = this.TRTransferMoney(Block, Body, BlockNum, TrNum, global.FORMAT_MONEY_TRANSFER, WorkStructTransfer)
break;
}
case TYPE_DEPRECATED_TRANSFER2:
{
Result = this.TRTransferMoney(Block, Body, BlockNum, TrNum, global.FORMAT_MONEY_TRANSFER2, WorkStructTransfer2)
break;
}
case TYPE_TRANSACTION_TRANSFER:
{
Result = this.TRTransferMoney(Block, Body, BlockNum, TrNum, global.FORMAT_MONEY_TRANSFER3, WorkStructTransfer3)
break;
}
case TYPE_TRANSACTION.TYPE_TRANSACTION_ACC_HASH:
{
Result = 1
if (global.LOCAL_RUN || global.TEST_NETWORK) {
} else {
if (BlockNum < global.START_BLOCK_ACCOUNT_HASH + 200000)
break;
}
var BlockNumHash = BlockNum - global.DELTA_BLOCK_ACCOUNT_HASH;
if (!this.TRCheckAccountHash(Body, BlockNum, TrNum)) {
Result = "BAD ACCOUNT HASH"
global.ToLog("2. ****FIND BAD ACCOUNT HASH IN BLOCK: " + BlockNumHash + " DO BLOCK=" + BlockNum)
} else {
Result = true
}
break;
}
}
return Result;
}
DoCoinBaseTR(Block) {
if (Block.BlockNum < global.START_MINING)
return;
var SysData = this.ReadStateTR(0);
var SysBalance = SysData.Value.SumCOIN;
const REF_PERIOD_START = global.START_MINING;
const REF_PERIOD_END = 30 * 1000 * 1000;
var AccountID = global.ReadUintFromArr(Block.AddrHash, 0);
if (AccountID < 8)
return;
var Data = this.ReadStateTR(AccountID);
if (Data && Data.Currency === 0 && Data.BlockNumCreate < Block.BlockNum) {
var Sum;
if (Block.BlockNum >= global.NEW_FORMULA_START) {
if (Block.BlockNum <= global.NEW_FORMULA_TARGET1) {
Sum = SysBalance * 43 * 43 / 100 / global.TOTAL_SUPPLY_TERA
var KMult = (global.NEW_FORMULA_TARGET2 - Block.BlockNum) / (global.NEW_FORMULA_TARGET2 - global.NEW_FORMULA_START);
Sum = KMult * Sum
}
else {
Sum = global.NEW_FORMULA_KTERA * SysBalance / global.TOTAL_SUPPLY_TERA
}
}
else {
var Power = global.GetPowPower(Block.PowHash);
if (Block.BlockNum >= global.NEW_BLOCK_REWARD1)
Power = 43
Sum = Power * Power * SysBalance / global.TOTAL_SUPPLY_TERA / 100
}
var CoinTotal = { SumCOIN: 0, SumCENT: 0 };
var CoinSum = global.COIN_FROM_FLOAT(Sum);
if (!global.ISZERO(CoinSum)) {
if (Data.Adviser >= 8 && Block.BlockNum < REF_PERIOD_END) {
var RefData = this.ReadStateTR(Data.Adviser);
if (RefData && RefData.BlockNumCreate < Block.BlockNum - global.REF_PERIOD_MINING) {
var K = (REF_PERIOD_END - Block.BlockNum) / (REF_PERIOD_END - REF_PERIOD_START);
var CoinAdv = global.COIN_FROM_FLOAT(Sum * K);
this.SendMoneyTR(Block, 0, Data.Adviser, CoinAdv, Block.BlockNum, 0xFFFF, "", "Adviser coin base [" + AccountID + "]", 1)
global.ADD(CoinTotal, CoinAdv)
global.ADD(CoinSum, CoinAdv)
}
}
this.SendMoneyTR(Block, 0, AccountID, CoinSum, Block.BlockNum, 0xFFFF, "", "Coin base", 1)
global.ADD(CoinTotal, CoinSum)
var CoinDevelop = global.CopyObjValue(CoinTotal);
global.DIV(CoinDevelop, 100)
if (!global.ISZERO(CoinDevelop))
this.SendMoneyTR(Block, 0, 9, CoinDevelop, Block.BlockNum, 0xFFFF, "", "Developers support", 1)
}
}
}
GetVerifyTransaction(Block, BlockNum, TrNum, Body) {
if (Block.VersionBody === 1) {
var Result = Block.arrContentResult[TrNum];
if (!Result)
return - 1;
else
return Result;
}
return 0;
}
GetObjectTransaction(Body) {
var Type = Body[0];
var format;
switch (Type) {
case TYPE_TRANSACTION.TYPE_TRANSACTION_CREATE:
{
format = global.FORMAT_CREATE
break;
}
case TYPE_DEPRECATED_TRANSFER1:
{
format = global.FORMAT_MONEY_TRANSFER
break;
}
case TYPE_DEPRECATED_TRANSFER2:
{
format = global.FORMAT_MONEY_TRANSFER2
break;
}
case TYPE_TRANSACTION_TRANSFER:
{
format = global.FORMAT_MONEY_TRANSFER3
break;
}
case TYPE_TRANSACTION.TYPE_TRANSACTION_ACC_HASH:
{
format = global.FORMAT_ACCOUNT_HASH3
break;
}
default:
return "";
}
var TR;
try {
TR = global.BufLib.GetObjectFromBuffer(Body, format, {})
} catch (e) {
}
return TR;
}
GetScriptTransaction(Body) {
var TR = this.GetObjectTransaction(Body);
if (!TR)
return "";
if (TR.Body && TR.Body.length) {
var App = global.DAppByType[TR.Body[0]];
if (App) {
TR.Body = JSON.parse(App.GetScriptTransaction(TR.Body))
}
}
global.ConvertBufferToStr(TR)
return JSON.stringify(TR, undefined, 2);
}
TRCheckAccountHash(Body, BlockNum, TrNum?) {
if (BlockNum % global.PERIOD_ACCOUNT_HASH !== 0) {
return 1;
}
try {
var TR = global.BufLib.GetObjectFromBuffer(Body, global.FORMAT_ACCOUNT_HASH3, {});
} catch (e) {
return 0;
}
if (BlockNum < global.START_BLOCK_ACCOUNT_HASH + 200000) {
return 1;
}
var Item = this.GetAccountHashItem(TR.BlockNum);
if (Item && Item.BlockNum === TR.BlockNum) {
if (global.CompareArr(Item.AccHash, TR.AccHash) === 0) {
if (TR.BlockNum >= global.START_BLOCK_ACCOUNT_HASH3) {
if (global.CompareArr(Item.SmartHash, TR.SmartHash) === 0 && Item.AccountMax === TR.AccountMax && Item.SmartCount === TR.SmartCount) {
return 1;
} else {
return 0;
}
}
return 1;
} else {
return 0;
}
} else {
return 2;
}
}
TRCreateAccount(Body, BlockNum, TrNum, ContextFrom) {
if (Body.length < 90)
return "Error length transaction";
var CheckMinPower = 1;
if (BlockNum >= 7000000 || global.LOCAL_RUN || global.TEST_NETWORK) {
if (ContextFrom && ContextFrom.To.length === 1 && ContextFrom.To[0].ID === 0 && ContextFrom.To[0].SumCOIN >= global.PRICE_DAO(BlockNum).NewAccount) {
CheckMinPower = 0
} else {
if (BlockNum % BLOCK_CREATE_INTERVAL !== 0)
return "The create transaction is not possible in this block: " + BlockNum;
if (this.CreateTrCount > 0)
return "The account creation transaction was already in this block: " + BlockNum;
}
}
this.CreateTrCount++
var power;
if (BlockNum >= global.BLOCKNUM_TICKET_ALGO) {
var Tr: any = { body: Body };
global.SERVER.CheckCreateTransactionObject(Tr)
power = Tr.power
}
else {
power = global.GetPowPower(global.shaarr(Body))
}
if (global.TEST_NETWORK && BlockNum >= 3290000) {
CheckMinPower = 0
}
if (CheckMinPower && BlockNum < 19600000) {
var MinPower;
if (BlockNum < 2500000)
MinPower = global.MIN_POWER_POW_ACC_CREATE
else
if (BlockNum < 2800000)
MinPower = global.MIN_POWER_POW_ACC_CREATE + 2
else
MinPower = global.MIN_POWER_POW_ACC_CREATE + 3
if (power < MinPower)
return "Error min power POW for create account (update client)";
}
try {
var TR = global.BufLib.GetObjectFromBuffer(Body, global.FORMAT_CREATE, {});
}
catch (e) {
return "Error transaction format";
}
if (BlockNum >= 3500000 && !TR.Name)
return "Account name required";
if (BlockNum >= 5700000 && !TR.Name.trim())
return "Account name required";
var Account = this.NewAccountTR(BlockNum, TrNum);
Account.Currency = TR.Currency
Account.PubKey = TR.PubKey
Account.Name = TR.Name
Account.Adviser = TR.Adviser
Account.Value.Smart = TR.Smart
this.WriteStateTR(Account, TrNum)
if (global.CompareArr(Account.PubKey, global.WALLET.PubKeyArr) === 0) {
global.WALLET.OnCreateAccount(Account)
}
this.ResultTx = Account.Num
return true;
}
TRTransferMoney(Block, Body, BlockNum, TrNum, format_money_transfer, workstructtransfer) {
if (Body.length < 103)
return "Error length transaction";
try {
var TR = global.BufLib.GetObjectFromBuffer(Body, format_money_transfer, workstructtransfer);
} catch (e) {
return "Error transaction format";
}
if (!TR.Version)
TR.Version = 0
var Data = this.ReadStateTR(TR.FromID);
if (!Data)
return "Error sender's account ID: " + TR.FromID;
if (TR.Version < 3 && TR.Currency !== Data.Currency)
return "Error sender's currency";
if (TR.Version < 3) {
if (TR.OperationID !== Data.Value.OperationID)
return "Error OperationID (expected: " + Data.Value.OperationID + " for ID: " + TR.FromID + ")";
} else {
if (TR.OperationID < Data.Value.OperationID)
return "Error OperationID (expected: " + Data.Value.OperationID + " for ID: " + TR.FromID + ")";
var MaxCountOperationID = 100;
if (BlockNum >= global.BLOCKNUM_TICKET_ALGO)
MaxCountOperationID = 1000000
if (TR.OperationID > Data.Value.OperationID + MaxCountOperationID)
return "Error too much OperationID (expected max: " + (Data.Value.OperationID + MaxCountOperationID) + " for ID: " + TR.FromID + ")";
}
if (BlockNum >= global.SMART_BLOCKNUM_START) {
if (TR.To.length > 10)
return "The number of recipients has been exceeded (max=5, current count=" + TR.To.length + ")";
}
if (TR.Body && TR.Body.length && TR.To.length > 1) {
return "Error - global.DApps transaction can not be used in a multiple transaction";
}
var TotalSum = { SumCOIN: 0, SumCENT: 0 };
var MapItem = {};
var bWas = 0;
for (var i = 0; i < TR.To.length; i++) {
var Item = TR.To[i];
if (Item.SumCOIN > MAX_SUM_TER)
return "Error MAX_SUM_COIN";
if (Item.SumCENT >= MAX_SUM_CENT)
return "Error MAX_SUM_CENT";
if (TR.Version < 3) {
if (Item.ID === TR.FromID || MapItem[Item.ID])
continue;
MapItem[Item.ID] = 1
}
bWas = 1
global.ADD(TotalSum, Item)
}
if (!bWas && TR.Version < 3)
return "No significant recipients";
var ZeroSum = 0;
if (TotalSum.SumCOIN === 0 && TotalSum.SumCENT === 0) {
if (TR.Version < 3)
return "No money transaction";
else
ZeroSum = 1
}
if (Data.Value.SumCOIN < TotalSum.SumCOIN || (Data.Value.SumCOIN === TotalSum.SumCOIN && Data.Value.SumCENT < TotalSum.SumCENT))
return "Not enough money on the account";
if (BlockNum >= global.NEW_ACCOUNT_INCREMENT)
Data.Value.OperationID = TR.OperationID
Data.Value.OperationID++
TR.Value = TotalSum
var arr = [];
MapItem = {}
var arrpub = [];
for (var i = 0; i < TR.To.length; i++) {
var Item = TR.To[i];
var DataTo = this.ReadStateTR(Item.ID);
if (!DataTo)
return "Error receiver account ID: " + Item.ID;
if (!ZeroSum && Data.Currency !== DataTo.Currency)
return "Error receiver currency";
for (var j = 0; j < 33; j++)
arrpub[arrpub.length] = DataTo.PubKey[j]
if (DataTo.Value.Smart) {
if (TR.To.length > 1)
return "Error - smart accounts can not be used in a multiple transaction";
}
if (TR.Version === 3 && Item.ID === 0 && Item.PubKey && Item.PubKey.length === 33) {
if (Item.SumCOIN < global.PRICE_DAO(BlockNum).NewAccount)
return "Not enough money for create account with index: " + i;
var name = TR.Description;
var index = name.indexOf("\n");
if (index !== - 1)
name = name.substr(0, index)
var Account = this.NewAccountTR(BlockNum, TrNum);
Account.PubKey = Item.PubKey
Account.Name = name
this.WriteStateTR(Account, TrNum)
this.ResultTx = Account.Num
Item.ID = Account.Num
this.SendMoneyTR(Block, Data.Num, Account.Num, { SumCOIN: Item.SumCOIN, SumCENT: Item.SumCENT }, BlockNum, TrNum, TR.Description,
TR.Description, 1)
this.SendMoneyTR(Block, Account.Num, 0, { SumCOIN: global.PRICE_DAO(BlockNum).NewAccount, SumCENT: 0 }, BlockNum, TrNum, "Fee for create account",
"", 1)
}
else {
if (TR.Version < 3) {
if (Item.ID === TR.FromID || MapItem[Item.ID])
continue;
MapItem[Item.ID] = 1
}
this.SendMoneyTR(Block, Data.Num, DataTo.Num, { SumCOIN: Item.SumCOIN, SumCENT: Item.SumCENT }, BlockNum, TrNum, TR.Description,
TR.Description, 0)
arr.push(DataTo)
}
}
if (TR.Version < 3 && arr.length === 0)
return "No recipients";
var hash;
if (TR.Version === 2 || TR.Version === 3) {
for (var j = 0; j < Body.length - 64 - 12; j++)
arrpub[arrpub.length] = Body[j]
hash = global.SHA3BUF(arrpub, BlockNum)
}
else
if (!TR.Version) {
hash = global.SHA3BUF(Body.slice(0, Body.length - 64 - 12), BlockNum)
}
else {
return "Error transaction version";
}
var Result: any = 0;
if (Data.PubKey[0] === 2 || Data.PubKey[0] === 3)
try {
Result = secp256k1.verify(hash, TR.Sign, Data.PubKey)
} catch (e) {
}
if (!Result) {
return "Error sign transaction";
}
if (TR.Body && TR.Body.length) {
var App = global.DAppByType[TR.Body[0]];
if (App) {
TR.FromPubKey = Data.PubKey
Result = App.OnWriteTransaction(Block, TR.Body, BlockNum, TrNum, TR);
if (Result as any !== true)
return Result;
}
}
return true;
}
ReadState(Num) {
var Data = this.DBState.Read(Num);
if (Data)
Data.WN = ""
return Data;
}
GetMinBlockAct() {
var DBAct;
var MaxNum = this.DBActPrev.GetMaxNum();
if (MaxNum === - 1)
DBAct = this.DBAct
else
DBAct = this.DBActPrev
var Item = DBAct.Read(0);
if (!Item)
return - 1;
else
return Item.BlockNum;
}
DeleteAct(BlockNumFrom) {
if (global.START_SERVER)
throw "DeleteAct START_SERVER";
if (BlockNumFrom > 0) {
var StateTX = this.DBStateTX.Read(0);
StateTX.BlockNum = BlockNumFrom - 1
this.DBStateTX.Write(StateTX)
}
this.DeleteActOneDB(this.DBAct, BlockNumFrom)
this.DeleteActOneDB(this.DBActPrev, BlockNumFrom)
this.DBAccountsHash.Truncate(Math.trunc(BlockNumFrom / global.PERIOD_ACCOUNT_HASH))
}
DeleteActOneDB(DBAct, BlockNum) {
var MaxNum = DBAct.GetMaxNum();
if (MaxNum === - 1)
return;
for (var num = MaxNum; num >= 0; num--) {
var ItemCheck = DBAct.Read(num);
if (!ItemCheck) {
global.ToLogTrace("!ItemCheck")
throw "ERRR DeleteActOneDB";
}
if (ItemCheck.BlockNum < BlockNum) {
this.ProcessingDeleteAct(DBAct, num + 1)
return;
}
}
this.ProcessingDeleteAct(DBAct, 0)
}
ProcessingDeleteAct(DBAct, StartNum) {
var Map = {};
var bWas = 0;
var NumTruncateState;
for (var num = StartNum; true; num++) {
var Item = DBAct.Read(num);
if (!Item)
break;
bWas = 1
if (Map[Item.ID])
continue;
Map[Item.ID] = 1
if (Item.Mode === 1) {
if (!NumTruncateState)
NumTruncateState = Item.ID
}
else {
var Data = this.DBState.Read(Item.ID);
Data.Value = Item.PrevValue
this._DBStateWrite(Data, Item.BlockNum, 1)
var History = this.DBStateHistory.Read(Item.ID);
if (History) {
History.NextPos = Item.PrevValue.NextPos
this.DBStateHistory.Write(History)
}
}
}
if (bWas) {
if (NumTruncateState) {
this._DBStateTruncate(NumTruncateState - 1)
this.DBStateHistory.Truncate(NumTruncateState - 1)
}
DBAct.Truncate(StartNum - 1)
}
}
FindBlockInAct(DBAct, BlockNum) {
return DBAct.FastFindBlockNum(BlockNum);
}
GetHole() {
return [{ s: 8300, f: 186478 }];
}
IsHole(num) {
if (global.ALL_VIEW_ROWS)
return 0;
var ArrHole = this.GetHole();
for (var i = 0; i < ArrHole.length; i++)
if (num >= ArrHole[i].s && num <= ArrHole[i].f)
return 1;
return 0;
}
FindAccounts(PubKeyArr, map, nSet) {
var Count = 0;
for (var num = 0; true; num++) {
if (this.IsHole(num))
continue;
var Data = this.ReadState(num);
if (!Data)
break;
for (var i = 0; i < PubKeyArr.length; i++)
if (global.CompareArr(Data.PubKey, PubKeyArr[i]) === 0) {
map[Data.Num] = i
Count++
}
}
return Count;
}
GetWalletAccountsByMap(map) {
var arr = [];
for (var key in map) {
var Num = parseInt(key);
var Data = this.ReadState(Num);
if (Data) {
if (!Data.PubKeyStr)
Data.PubKeyStr = global.GetHexFromArr(Data.PubKey)
arr.push(Data)
Data.WN = map[key]
Data.Name = global.NormalizeName(Data.Name)
if (Data.Currency)
Data.CurrencyObj = global.DApps.Smart.ReadSimple(Data.Currency)
if (Data.Value.Smart) {
Data.SmartObj = global.DApps.Smart.ReadSimple(Data.Value.Smart)
if (Data.SmartObj)
Data.SmartState = this.GetSmartState(Data, Data.SmartObj.StateFormat)
else
Data.SmartState = {}
}
}
}
return arr;
}
GetMaxAccount() {
return this.DBState.GetMaxNum();
}
GetRowsAccounts(start, count, Filter?, bGetState?) {
if (Filter) {
Filter = Filter.trim()
}
var F;
if (Filter) {
if (Filter.substring(0, 1) === "=") {
Filter = Filter.substring(1)
try {
F = global.CreateEval(Filter, "Cur,Currency,ID,Operation,Amount,Adviser,Name,PubKey,Smart,BlockNum")
} catch (e) {
F = undefined
global.ToLog("" + e)
}
} else {
Filter = Filter.toUpperCase()
}
}
var WasError = 0;
var arr = [];
for (var num = start; true; num++) {
if (this.IsHole(num))
continue;
var Data = this.ReadState(num);
if (!Data)
break;
if (!Data.PubKeyStr)
Data.PubKeyStr = global.GetHexFromArr(Data.PubKey)
Data.Name = global.NormalizeName(Data.Name)
if (F) {
var Cur = Data.Currency;
var Currency = Data.Currency;
var ID = Data.Num;
var Operation = Data.Value.OperationID;
var Amount = global.FLOAT_FROM_COIN(Data.Value);
var Adviser = Data.Adviser;
var Name = Data.Name;
var PubKey = global.GetHexFromArr(Data.PubKey);
var Smart = Data.Value.Smart;
try {
if (!F(Cur, Currency, ID, Operation, Amount, Adviser, Name, PubKey, Smart, Data.BlockNumCreate))
continue;
}
catch (e) {
if (!WasError)
global.ToLog("" + e)
WasError = 1
}
}
else
if (Filter) {
var Amount = global.FLOAT_FROM_COIN(Data.Value);
var PubKey = global.GetHexFromArr(Data.PubKey);
var Str = "" + Data.Num + " " + Data.Value.OperationID + " " + Data.Name.toUpperCase() + " " + Data.Adviser + " " + Amount + " " + PubKey + " " + Smart + " " + Data.BlockNumCreate;
if (Str.indexOf(Filter) < 0)
continue;
}
if (bGetState) {
if (Data.Currency)
Data.CurrencyObj = global.DApps.Smart.ReadSimple(Data.Currency)
if (Data.Value.Smart) {
Data.SmartObj = global.DApps.Smart.ReadSimple(Data.Value.Smart)
if (Data.SmartObj)
Data.SmartState = this.GetSmartState(Data, Data.SmartObj.StateFormat)
else
Data.SmartState = {}
}
}
arr.push(Data)
count--
if (count < 1)
break;
}
return arr;
}
GetSmartState(StateData, StateFormat) {
var SmartState;
try {
SmartState = global.BufLib.GetObjectFromBuffer(StateData.Value.Data, StateFormat, {})
if (typeof SmartState === "object")
SmartState.Num = StateData.Num
}
catch (e) {
SmartState = {}
}
return SmartState;
}
GetActsMaxNum() {
return this.DBActPrev.GetMaxNum() + this.DBAct.GetMaxNum();
}
GetActList(start, count, b?) {
var arr = [];
var num;
for (num = start; num < start + count; num++) {
var Item = this.DBActPrev.Read(num);
if (!Item)
break;
Item.Num = "Prev." + Item.Num
if (Item.TrNum === 0xFFFF)
Item.TrNum = ""
arr.push(Item)
if (arr.length > count)
return arr;
}
start = num - this.DBActPrev.GetMaxNum() - 1
for (num = start; num < start + count; num++) {
var Item = this.DBAct.Read(num);
if (!Item)
break;
Item.Num = Item.Num
if (Item.TrNum === 0xFFFF)
Item.TrNum = ""
arr.push(Item)
if (arr.length > count)
return arr;
}
return arr;
}
GetHashOrUndefined(BlockNum) {
if (BlockNum % global.PERIOD_ACCOUNT_HASH !== 0)
return undefined;
var Item = this.GetAccountHashItem(BlockNum);
if (Item)
return Item.AccHash;
else
return undefined;
}
GetAccountHashItem(BlockNum) {
var Item = this.DBAccountsHash.Read(Math.trunc(BlockNum / global.PERIOD_ACCOUNT_HASH));
return Item;
}
GetHashedMaxBlockNum() {
var Num = this.DBAccountsHash.GetMaxNum();
if (Num >= 0) {
var Data = this.DBAccountsHash.Read(Num);
return Data.BlockNum;
}
else
return 0;
}
CalcHash(Block, BlockMaxAccount) {
if (Block.BlockNum % global.PERIOD_ACCOUNT_HASH !== 0)
return;
if (this.DBState.WasUpdate) {
this.CalcMerkleTree()
}
var Hash = this.DBState.MerkleHash;
var SmartHash;
var SmartCount = global.DApps.Smart.GetMaxNum() + 1;
if (SmartCount > 0) {
var MaxSmart = global.DApps.Smart.DBSmart.Read(SmartCount - 1);
SmartHash = MaxSmart.SumHash
}
else {
SmartHash = []
}
var Data = {
Num: Block.BlockNum / global.PERIOD_ACCOUNT_HASH, BlockNum: Block.BlockNum, AccHash: Hash, SumHash: Block.SumHash, AccountMax: BlockMaxAccount,
SmartHash: SmartHash, SmartCount: SmartCount
};
this.DBAccountsHash.Write(Data)
this.DBAccountsHash.Truncate(Block.BlockNum / global.PERIOD_ACCOUNT_HASH)
return Data;
}
CalcMerkleTree(bForce?) {
this.DBState.MerkleHash = this.DBState.CalcMerkleTree(bForce)
this.DBState.WasUpdate = 0
}
GetAdviserByMiner(Map, Id) {
var Adviser = Map[Id];
if (Adviser === undefined) {
var Item = this.ReadState(Id);
if (Item)
Adviser = Item.Adviser
else
Adviser = 0
Map[Id] = Adviser
}
return Adviser;
}
BeginBlock() {
this.DBChanges = { BlockMap: {}, BlockMaxAccount: this.GetMaxAccount(), BlockHistory: [], BlockEvent: [], }
}
BeginTransaction() {
global.TickCounter = 35000
this.DBChanges.TRMap = {}
this.DBChanges.TRMaxAccount = this.DBChanges.BlockMaxAccount
this.DBChanges.RollBackTransaction = 0
this.DBChanges.TRHistory = []
this.DBChanges.TREvent = []
}
RollBackTransaction() {
this.DBChanges.RollBackTransaction = 1
}
CommitBlock(Block) {
var BlockNum = Block.BlockNum;
var DBChanges = this.DBChanges;
for (var i = 0; i < DBChanges.BlockHistory.length; i++) {
var Data = DBChanges.BlockHistory[i];
var Account = DBChanges.BlockMap[Data.CurID];
Data.Type = 1
Data.NextPos = Account.Value.NextPos
Account.Value.NextPos = this.SaveHistory(Data)
}
var arr = [];
for (var key in DBChanges.BlockMap) {
key = global.ParseNum(key)
var Data = DBChanges.BlockMap[key];
if (Data.Changed) {
arr.push(Data)
}
}
arr.sort(function(a, b) {
return a.Num - b.Num;
})
for (var i = 0; i < arr.length; i++) {
var Account = arr[i];
var BackLog = {
Num: undefined, ID: Account.Num, BlockNum: BlockNum, PrevValue: Account.BackupValue, TrNum: Account.ChangeTrNum,
Mode: Account.New
};
this.DBAct.Write(BackLog)
}
for (var i = 0; i < arr.length; i++) {
var Account = arr[i];
this._DBStateWrite(Account, BlockNum, 0)
}
for (var i = 0; i < arr.length; i++) {
var Account = arr[i];
var History = { Num: Account.Num, NextPos: Account.Value.NextPos };
this.DBStateHistory.Write(History)
}
for (var i = 0; i < DBChanges.BlockEvent.length; i++) {
var Data = DBChanges.BlockEvent[i];
var Has = global.TreeFindTX.LoadValue("Smart:" + Data.Smart, 1);
if (Has) {
process.send({ cmd: "DappEvent", Data: Data })
}
}
global.TickCounter = 0
this.DBChanges = undefined
this.CalcHash(Block, DBChanges.BlockMaxAccount)
var StateTX = this.DBStateTX.Read(0);
StateTX.BlockNum = BlockNum
this.DBStateTX.Write(StateTX)
}
CommitTransaction(BlockNum, TrNum) {
var DBChanges = this.DBChanges;
if (DBChanges.RollBackTransaction)
return false;
DBChanges.BlockMaxAccount = DBChanges.TRMaxAccount
for (var key in DBChanges.TRMap) {
key = global.ParseNum(key)
var Data = DBChanges.TRMap[key];
if (Data.Changed) {
DBChanges.BlockMap[key] = Data
if (Data.New)
this.OnWriteNewAccountTR(Data, BlockNum, TrNum)
}
}
for (var i = 0; i < DBChanges.TRHistory.length; i++)
DBChanges.BlockHistory.push(DBChanges.TRHistory[i])
for (var i = 0; i < DBChanges.TREvent.length; i++) {
DBChanges.BlockEvent.push(DBChanges.TREvent[i])
}
global.TickCounter = 0
return true;
}
OnWriteNewAccountTR(Data, BlockNum, TrNum) {
if (BlockNum < global.SMART_BLOCKNUM_START)
Data.Value.Smart = 0
Data.BlockNumCreate = BlockNum
if (Data.Adviser > this.GetMaxAccount())
Data.Adviser = 0
if (Data.Value.Smart > global.DApps.Smart.GetMaxNum())
Data.Value.Smart = 0
if (Data.Currency > global.DApps.Smart.GetMaxNum())
Data.Currency = 0
if (Data.Currency) {
var Smart = global.DApps.Smart.ReadSmart(Data.Currency);
if (!Smart || !Smart.TokenGenerate)
Data.Currency = 0
}
}
NewAccountTR(BlockNum, TrNum) {
var DBChanges = this.DBChanges;
DBChanges.TRMaxAccount++
var Data: any = {
Num: DBChanges.TRMaxAccount, New: 1, Changed: 1, ChangeTrNum: TrNum, BackupValue: {}, PubKey: [], Currency: 0, Adviser: 0,
Value: { SumCOIN: 0, SumCENT: 0, OperationID: 0, Smart: 0, Data: [] }
};
this.DBChanges.TRMap[Data.Num] = Data
return Data;
}
ReadStateTR(Num) {
Num = global.ParseNum(Num)
var TRMap = this.DBChanges.TRMap;
var Data = TRMap[Num];
if (!Data) {
var Value;
var BlockMap = this.DBChanges.BlockMap;
var BData = BlockMap[Num];
if (!BData) {
BData = this.DBState.Read(Num)
if (!BData)
return undefined;
BData.Num = Num
Value = BData.Value
var BHistory = this.DBStateHistory.Read(Num);
if (BHistory)
Value.NextPos = BHistory.NextPos
BData.BackupValue = {
SumCOIN: Value.SumCOIN, SumCENT: Value.SumCENT, OperationID: Value.OperationID, Smart: Value.Smart, Data: Value.Data,
NextPos: Value.NextPos
}
BlockMap[Num] = BData
}
Value = BData.Value
Data = {
Num: Num, Currency: BData.Currency, PubKey: BData.PubKey, Name: BData.Name, BlockNumCreate: BData.BlockNumCreate, Adviser: BData.Adviser,
Value: {
SumCOIN: Value.SumCOIN, SumCENT: Value.SumCENT, OperationID: Value.OperationID, Smart: Value.Smart, Data: global.CopyArr(Value.Data),
NextPos: Value.NextPos
}, BackupValue: BData.BackupValue
}
TRMap[Num] = Data
}
return Data;
}
WriteStateTR(Data, TrNum) {
Data.Changed = 1
Data.ChangeTrNum = TrNum
}
SendMoneyTR(Block, FromID, ToID, CoinSum, BlockNum, TrNum, DescriptionFrom, DescriptionTo, OperationCount) {
FromID = global.ParseNum(FromID)
ToID = global.ParseNum(ToID)
if (CoinSum.SumCENT >= 1e9) {
throw "ERROR SumCENT>=1e9";
}
var FromData = this.ReadStateTR(FromID);
if (!FromData) {
throw "Send: Error account FromNum: " + FromID;
}
if (!global.SUB(FromData.Value, CoinSum)) {
throw "Not enough money on the account ID:" + FromID;
}
this.WriteStateTR(FromData, TrNum)
if (FromID > 15) {
this.DBChanges.TRHistory.push({
Direct: "-", Receive: 0, CurID: FromID, CorrID: ToID, BlockNum: BlockNum, TrNum: TrNum, FromID: FromID,
ToID: ToID, SumCOIN: CoinSum.SumCOIN, SumCENT: CoinSum.SumCENT, Description: DescriptionFrom, FromOperationID: FromData.Value.OperationID,
Currency: FromData.Currency
})
}
var ToData = this.ReadStateTR(ToID);
if (!ToData) {
throw "Send: Error account ToNum: " + ToID;
}
global.ADD(ToData.Value, CoinSum)
this.WriteStateTR(ToData, TrNum)
if (ToID > 15) {
this.DBChanges.TRHistory.push({
Direct: "+", Receive: 1, CurID: ToID, CorrID: FromID, BlockNum: BlockNum, TrNum: TrNum, FromID: FromID,
ToID: ToID, SumCOIN: CoinSum.SumCOIN, SumCENT: CoinSum.SumCENT, Description: DescriptionTo, FromOperationID: FromData.Value.OperationID,
Currency: ToData.Currency
})
}
FromData.Value.OperationID += OperationCount
if (FromData.Value.Smart) {
var Context = { FromID: FromID, ToID: ToID, Description: DescriptionFrom, Value: CoinSum };
global.RunSmartMethod(Block, FromData.Value.Smart, FromData, BlockNum, TrNum, Context, "OnSend")
}
if (ToData.Value.Smart) {
var Context = { FromID: FromID, ToID: ToID, Description: DescriptionTo, Value: CoinSum };
global.RunSmartMethod(Block, ToData.Value.Smart, ToData, BlockNum, TrNum, Context, "OnGet")
}
}
GetSignTransferTx(TR, PrivKey) {
var Arr;
if (TR.Version === 2 || TR.Version === 3) {
var format;
if (TR.Version === 2)
format = global.FORMAT_MONEY_TRANSFER_BODY2
else
format = global.FORMAT_MONEY_TRANSFER_BODY3
Arr = []
for (var i = 0; i < TR.To.length; i++) {
var Item = TR.To[i];
var DataTo = global.DApps.Accounts.ReadState(Item.ID);
if (!DataTo)
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, 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 j = 0; j < 33; j++)
Arr[Arr.length] = DataTo.PubKey[j]
}
var Body = global.BufLib.GetBufferFromObject(TR, format, global.MAX_TRANSACTION_SIZE, {});
for (var j = 0; j < Body.length; j++)
Arr[Arr.length] = Body[j]
}
else {
Arr = global.BufLib.GetBufferFromObject(TR, global.FORMAT_MONEY_TRANSFER_BODY, global.MAX_TRANSACTION_SIZE, {})
}
var sigObj = secp256k1.sign(global.SHA3BUF(Arr), Buffer.from(PrivKey));
return sigObj.signature;
}
SaveHistory(Data) {
var FileItem = global.HistoryDB.OpenDBFile(FILE_NAME_HISTORY, 1);
var FD = FileItem.fd;
var Position = FileItem.size;
if (!Position)
Position = 100
var BufWrite = global.BufLib.GetBufferFromObject(Data, this.HistoryFormatArr[Data.Type], 100, WorkStructHistory);
var written = fs.writeSync(FD, BufWrite, 0, BufWrite.length, Position);
if (written !== BufWrite.length) {
global.TO_ERROR_LOG("DB-HISTORY", 10, "Error write to file:" + written + " <> " + BufWrite.length)
throw "Error write to FILE_NAME_HISTORY";
return false;
}
if (Position >= FileItem.size) {
FileItem.size = Position + written
}
return Position;
}
GetHistory(Num, Count, StartPos, MinConfirm?) {
if (!MinConfirm)
MinConfirm = 0
var MaxNumBlockDB = global.SERVER.GetMaxNumBlockDB();
var Position = StartPos;
var FileItem = global.HistoryDB.OpenDBFile(FILE_NAME_HISTORY, 0);
var FD = FileItem.fd;
if (Position === undefined) {
var Account = this.DBStateHistory.Read(Num);
if (!Account) {
return [];
}
Position = Account.NextPos
}
var arr = [];
while (Count > 0 && Position) {
Count--
var BufRead = global.BufLib.GetNewBuffer(100);
var bytesRead = fs.readSync(FD, BufRead, 0, BufRead.length, Position);
if (bytesRead < 13) {
global.ToLog("bytesRead<13 Position=" + Position)
break;
}
var Type = BufRead[0];
var format = this.HistoryFormatArr[Type];
if (!format) {
global.ToLog("Error from history, type = " + Type)
break;
}
var Item = global.BufLib.GetObjectFromBuffer(BufRead, format, WorkStructHistory);
Item.Pos = Position
Position = Item.NextPos
if (MinConfirm) {
if (Item.BlockNum + MinConfirm > MaxNumBlockDB) {
continue;
}
}
arr.push(Item)
}
return arr;
}
CalcTotalSum(Currency) {
var SumCoin = { SumCOIN: 0, SumCENT: 0 };
for (var num = 0; true; num++) {
var Data = this.ReadState(num);
if (!Data)
break;
if (Data.Currency === Currency) {
global.ADD(SumCoin, Data.Value)
}
}
return global.FLOAT_FROM_COIN(SumCoin);
}
};
var App = new AccountApp;
global.DApps["Accounts"] = App;
global.DAppByType[TYPE_TRANSACTION.TYPE_TRANSACTION_CREATE] = App;
global.DAppByType[TYPE_DEPRECATED_TRANSFER1] = App;
global.DAppByType[TYPE_DEPRECATED_TRANSFER2] = App;
global.DAppByType[TYPE_TRANSACTION_TRANSFER] = App;
global.DAppByType[TYPE_TRANSACTION.TYPE_TRANSACTION_ACC_HASH] = App;
// function TestStateFiles(Size, Format) {
// return;
// if (global.PROCESS_NAME !== "MAIN")
// return;
// var DBState1 = new DBRow("state-ok", Size, Format, 0);
// var DBState2 = new DBRow("state-no", Size, Format, 0);
// for (var Num = 0; 1; Num++) {
// var Item1 = DBState1.Read(Num);
// var Item2 = DBState2.Read(Num);
// if (!Item1 && !Item2)
// break;
// var Str1 = JSON.stringify(Item1);
// var Str2 = JSON.stringify(Item2);
// if (Str1 !== Str2) {
// global.ToLog("Err item: " + Num);
// global.ToLog("1: " + Str1);
// global.ToLog("2: " + Str2);
// }
// }
// };