tera/src/system/smart.ts

1222 lines
37 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 DApp from './dapp'
import DBRow from '../core/db/db-row'
import { secp256k1 } from '../core/library'
const LOC_ADD_NAME = "$";
require("../HTML/JS/lexer.js");
global.TickCounter = 0;
const TYPE_TRANSACTION_SMART_CREATE = 130;
global.TYPE_TRANSACTION_SMART_RUN = 135;
const TYPE_TRANSACTION_SMART_CHANGE = 140;
global.FORMAT_SMART_CREATE = "{\
Type:byte,\
TokenGenerate:byte,\
StartValue:uint,\
OwnerPubKey:byte,\
ISIN:str,\
Zip:byte,\
AccountLength:byte,\
StateFormat:str,\
Category1:byte,\
Category2:byte,\
Category3:byte,\
Reserve:arr20,\
IconBlockNum:uint,\
IconTrNum:uint16,\
ShortName:str5,\
Name:str,\
Description:str,\
Code:str,\
HTML:str,\
}";
const WorkStructCreate = {};
global.FORMAT_SMART_RUN = "{\
Type:byte,\
Account:uint,\
MethodName:str,\
Params:str,\
FromNum:uint,\
OperationID:uint,\
Reserve:arr10,\
Sign:arr64,\
}";
//@ts-ignore
const WorkStructRun = {};
global.FORMAT_SMART_CHANGE = "{\
Type:byte,\
Account:uint,\
Smart:uint32,\
Reserve:arr10,\
FromNum:uint,\
OperationID:uint,\
Sign:arr64,\
}";
const WorkStructChange = {};
class SmartApp extends DApp {
FORMAT_ROW
ROW_SIZE
DBSmart
RowHole
constructor() {
super()
var bReadOnly = (global.PROCESS_NAME !== "TX");
this.FORMAT_ROW = "{\
Version:byte,\
TokenGenerate:byte,\
ISIN:str12,\
Zip:byte,\
BlockNum:uint,\
TrNum:uint16,\
IconBlockNum:uint,\
IconTrNum:uint16,\
ShortName:str5,\
Name:str40,\
Account:uint,\
AccountLength:byte,\
Category1:byte,\
Category2:byte,\
Category3:byte,\
Owner:uint,\
Reserve:arr20,\
StateFormat:str,\
Description:str,\
Code:str,\
HTML:str,\
SumHash:hash,\
}"
this.ROW_SIZE = 2 * (1 << 13)
this.DBSmart = new DBRow("smart", this.ROW_SIZE, this.FORMAT_ROW, bReadOnly)
this.InitHole()
if (!bReadOnly)
this.Start()
}
Start() {
if (this.GetMaxNum() + 1 >= 7)
return;
this.DBSmartWrite({ Num: 0, ShortName: "TERA", Name: "TERA", Description: "TERA", BlockNum: 0, TokenGenerate: 1, Account: 0, Category1: 0 })
for (var i = 1; i < 8; i++)
this.DBSmartWrite({ Num: i, ShortName: "", Name: "", Description: "", BlockNum: 0, TokenGenerate: 1, Account: i, Category1: 0 })
}
Close() {
this.DBSmart.Close()
}
ClearDataBase() {
this.DBSmart.Truncate(- 1)
this.Start()
}
GetSenderNum(BlockNum, Body) {
var Type = Body[0];
if (Type && Body.length > 90) {
switch (Type) {
case global.TYPE_TRANSACTION_SMART_RUN:
var len = 1 + 6;
len += 2 + Body[len] + Body[len + 1] * 256
if (len + 64 > Body.length)
return 0;
len += 2 + Body[len] + Body[len + 1] * 256
if (len + 64 > Body.length)
return 0;
var Num = global.ReadUintFromArr(Body, len);
return Num;
case TYPE_TRANSACTION_SMART_CHANGE:
var Num = global.ReadUintFromArr(Body, 1);
return Num;
}
}
return 0;
}
OnDeleteBlock(Block) {
if (Block.BlockNum < 1)
return;
this.DBSmart.DeleteHistory(Block.BlockNum)
}
OnWriteBlockStart(Block) {
if (Block.BlockNum < 1)
return;
this.OnDeleteBlock(Block)
}
OnWriteBlockFinish(Block) {
}
OnWriteTransaction(Block, Body, BlockNum, TrNum, ContextFrom) {
var Type = Body[0];
if (!ContextFrom) {
global.DApps.Accounts.BeginTransaction()
}
var Result;
try {
switch (Type) {
case TYPE_TRANSACTION_SMART_CREATE:
Result = this.TRCreateSmart(Block, Body, BlockNum, TrNum, ContextFrom)
break;
case global.TYPE_TRANSACTION_SMART_RUN:
Result = this.TRRunSmart(Block, Body, BlockNum, TrNum, ContextFrom)
break;
case TYPE_TRANSACTION_SMART_CHANGE:
Result = this.TRChangeSmart(Block, Body, BlockNum, TrNum, ContextFrom)
break;
}
}
catch (e) {
Result = "" + e
}
return Result;
}
GetScriptTransaction(Body) {
var Type = Body[0];
var format;
if (Type === TYPE_TRANSACTION_SMART_CREATE)
format = global.FORMAT_SMART_CREATE
else
if (Type === global.TYPE_TRANSACTION_SMART_RUN)
format = global.FORMAT_SMART_RUN
else
if (Type === TYPE_TRANSACTION_SMART_CHANGE)
format = global.FORMAT_SMART_CHANGE
if (!format)
return "";
var TR = global.BufLib.GetObjectFromBuffer(Body, format, {});
global.ConvertBufferToStr(TR)
return JSON.stringify(TR, undefined, 2);
}
GetVerifyTransaction(Block, BlockNum, TrNum, Body) {
return 1;
}
TRCreateSmart(Block, Body, BlockNum, TrNum, ContextFrom) {
if (!ContextFrom)
return "Pay context required";
if (Body.length < 31)
return "Error length transaction (min size)";
if (Body.length > 16000)
return "Error length transaction (max size)";
if (BlockNum < global.SMART_BLOCKNUM_START)
return "Error block num";
var TR = global.BufLib.GetObjectFromBuffer(Body, global.FORMAT_SMART_CREATE, WorkStructCreate);
if (!TR.Name.trim())
return "Name required";
if (TR.AccountLength > 50)
return "Error AccountLength=" + TR.AccountLength;
if (TR.AccountLength < 1)
TR.AccountLength = 1
var AddAccount = TR.AccountLength - 1;
var Price;
if (TR.TokenGenerate)
Price = global.PRICE_DAO(BlockNum).NewTokenSmart
else
Price = global.PRICE_DAO(BlockNum).NewSmart
Price += AddAccount * global.PRICE_DAO(BlockNum).NewAccount
if (!(ContextFrom && ContextFrom.To.length === 1 && ContextFrom.To[0].ID === 0 && ContextFrom.To[0].SumCOIN >= Price)) {
return "Not money in the transaction";
}
ContextFrom.ToID = ContextFrom.To[0].ID
var Smart = TR;
Smart.Version = 0
Smart.Zip = 0
Smart.BlockNum = BlockNum
Smart.TrNum = TrNum
Smart.Reserve = []
Smart.Num = undefined
Smart.Owner = ContextFrom.FromID
this.DBSmart.CheckNewNum(Smart)
var Account = global.DApps.Accounts.NewAccountTR(BlockNum, TrNum);
Account.Value.Smart = Smart.Num
Account.Name = TR.Name
if (Smart.TokenGenerate) {
Account.Currency = Smart.Num
Account.Value.SumCOIN = TR.StartValue
}
if (TR.OwnerPubKey)
Account.PubKey = ContextFrom.FromPubKey
global.DApps.Accounts.WriteStateTR(Account, TrNum)
for (var i = 0; i < AddAccount; i++) {
var CurAccount = global.DApps.Accounts.NewAccountTR(BlockNum, TrNum);
CurAccount.Value.Smart = Smart.Num
CurAccount.Name = TR.Name
if (Smart.TokenGenerate)
CurAccount.Currency = Smart.Num
if (TR.OwnerPubKey)
CurAccount.PubKey = ContextFrom.FromPubKey
global.DApps.Accounts.WriteStateTR(CurAccount, TrNum)
}
Smart.Account = Account.Num
this.DBSmart.DeleteMap("EVAL" + Smart.Num)
try {
RunSmartMethod(Block, Smart, Account, BlockNum, TrNum, ContextFrom, "OnCreate")
}
catch (e) {
this.DBSmart.DeleteMap("EVAL" + Smart.Num)
return e;
}
this.DBSmartWrite(Smart)
return true;
}
CheckSignFrom(Body, TR, BlockNum, TrNum) {
var ContextFrom = { FromID: TR.FromNum };
var AccountFrom = global.DApps.Accounts.ReadStateTR(TR.FromNum);
if (!AccountFrom)
return "Error account FromNum: " + TR.FromNum;
if (TR.OperationID < AccountFrom.Value.OperationID)
return "Error OperationID (expected: " + AccountFrom.Value.OperationID + " for ID: " + TR.FromNum + ")";
var MaxCountOperationID = 100;
if (BlockNum >= global.BLOCKNUM_TICKET_ALGO)
MaxCountOperationID = 1000000
if (TR.OperationID > AccountFrom.Value.OperationID + MaxCountOperationID)
return "Error too much OperationID (expected max: " + (AccountFrom.Value.OperationID + MaxCountOperationID) + " for ID: " + TR.FromNum + ")";
var hash = global.SHA3BUF(Body.slice(0, Body.length - 64 - 12), BlockNum);
var Result: any = 0;
if (AccountFrom.PubKey[0] === 2 || AccountFrom.PubKey[0] === 3)
try {
Result = secp256k1.verify(hash, TR.Sign, AccountFrom.PubKey)
} catch (e) {
}
if (!Result) {
return "Error sign transaction";
}
if (BlockNum >= 13000000) {
AccountFrom.Value.OperationID = TR.OperationID + 1
global.DApps.Accounts.WriteStateTR(AccountFrom, TrNum)
}
else
if (AccountFrom.Value.OperationID !== TR.OperationID) {
AccountFrom.Value.OperationID = TR.OperationID
global.DApps.Accounts.WriteStateTR(AccountFrom, TrNum)
}
return ContextFrom;
}
TRRunSmart(Block, Body, BlockNum, TrNum, ContextFrom) {
if (Body.length < 100)
return "Error length transaction (min size)";
if (BlockNum < global.SMART_BLOCKNUM_START)
return "Error block num";
var TR = global.BufLib.GetObjectFromBuffer(Body, global.FORMAT_SMART_RUN, WorkStructRun);
var Account = global.DApps.Accounts.ReadStateTR(TR.Account);
if (!Account)
return "RunSmart: Error account Num: " + TR.Account;
if (!ContextFrom && TR.FromNum) {
var ResultCheck = this.CheckSignFrom(Body, TR, BlockNum, TrNum);
if (typeof ResultCheck === "string")
return ResultCheck;
ContextFrom = ResultCheck
}
try {
var Params = JSON.parse(TR.Params);
RunSmartMethod(Block, Account.Value.Smart, Account, BlockNum, TrNum, ContextFrom, TR.MethodName, Params, 1)
}
catch (e) {
return e;
}
return true;
}
TRChangeSmart(Block, Body, BlockNum, TrNum, ContextFrom) {
if (Body.length < 21)
return "Error length transaction (min size)";
if (BlockNum < global.SMART_BLOCKNUM_START)
return "Error block num";
var TR = global.BufLib.GetObjectFromBuffer(Body, global.FORMAT_SMART_CHANGE, WorkStructChange);
if (!ContextFrom) {
var ResultCheck = this.CheckSignFrom(Body, TR, BlockNum, TrNum);
if (typeof ResultCheck === "string")
return ResultCheck;
ContextFrom = ResultCheck
}
if (TR.Smart > this.GetMaxNum())
TR.Smart = 0
if (ContextFrom.FromID !== TR.Account)
return "ChangeSmart: Error account FromNum: " + TR.Account;
var Account = global.DApps.Accounts.ReadStateTR(TR.Account);
if (!Account)
return "Error read account Num: " + TR.Account;
if (BlockNum >= 13000000) {
if (Account.Value.Smart === TR.Smart)
return "The value has not changed";
}
if (Account.Value.Smart) {
var Smart = this.ReadSmart(Account.Value.Smart);
if (Smart.Account === TR.Account)
return "Can't change base account";
try {
RunSmartMethod(Block, Account.Value.Smart, Account, BlockNum, TrNum, ContextFrom, "OnDeleteSmart")
}
catch (e) {
return e;
}
}
Account.Value.Smart = TR.Smart
Account.Value.Data = []
global.DApps.Accounts.WriteStateTR(Account, TrNum)
if (Account.Value.Smart) {
try {
RunSmartMethod(Block, Account.Value.Smart, Account, BlockNum, TrNum, ContextFrom, "OnSetSmart")
}
catch (e) {
return e;
}
}
return true;
}
GetRows(start, count, Filter, Category, GetAllData, bTokenGenerate?) {
if (Filter) {
Filter = Filter.trim()
Filter = Filter.toUpperCase()
}
if (Category)
Category = global.ParseNum(Category)
var WasError = 0;
var arr = [];
var Data;
for (var num = start; true; num++) {
if (this.IsHole(num))
continue;
if (GetAllData)
Data = this.ReadSmart(num)
else
Data = this.ReadSimple(num)
if (!Data)
break;
if (bTokenGenerate && !Data.TokenGenerate)
continue;
if (Category) {
if (Data.Category1 !== Category && Data.Category2 !== Category && Data.Category3 !== Category)
continue;
}
if (Filter) {
var Str = "" + Data.ShortName.toUpperCase() + Data.ISIN.toUpperCase() + Data.Name.toUpperCase() + Data.Description.toUpperCase();
if (Data.TokenGenerate)
Str += "TOKEN GENERATE"
if (Str.indexOf(Filter) < 0)
continue;
}
var CanAdd = 1;
var DataState = global.DApps.Accounts.ReadState(Data.Account);
if (DataState && !global.ALL_VIEW_ROWS) {
Data.BaseState = global.DApps.Accounts.GetSmartState(DataState, Data.StateFormat)
if (typeof Data.BaseState === "object" && Data.BaseState.HTMLBlock === 404)
CanAdd = 0
}
if (CanAdd) {
arr.push(Data)
}
count--
if (count < 1)
break;
}
return arr;
}
GetMaxNum() {
return this.DBSmart.GetMaxNum();
}
DBSmartWrite(Item) {
var PrevNum;
if (Item.Num === undefined)
PrevNum = this.GetMaxNum()
else
PrevNum = Item.Num - 1
Item.SumHash = []
var Buf = global.BufLib.GetBufferFromObject(Item, this.FORMAT_ROW, 20000, {});
var Hash = global.sha3(Buf);
if (PrevNum < 0)
Item.SumHash = Hash
else {
var PrevItem = this.DBSmart.Read(PrevNum);
if (!PrevItem) {
throw "!PrevItem of Smart num = " + PrevNum;
}
Item.SumHash = global.sha3arr2(PrevItem.SumHash, Hash)
}
this.DBSmart.Write(Item)
}
ReadSmart(Num) {
Num = global.ParseNum(Num)
var Smart = this.DBSmart.GetMap("ITEM" + Num);
if (!Smart) {
Smart = this.DBSmart.Read(Num)
if (Smart) {
if (!Smart.WorkStruct)
Smart.WorkStruct = {}
Smart.CodeLength = Smart.Code.length
Smart.HTMLLength = Smart.HTML.length
this.DBSmart.SetMap("ITEM" + Num, Smart)
}
}
return Smart;
}
ReadSimple(Num) {
var Smart = this.DBSmart.GetMap("SIMPLE" + Num);
if (!Smart) {
Smart = this.DBSmart.Read(Num)
if (Smart) {
Smart.CodeLength = Smart.Code.length
Smart.HTMLLength = Smart.HTML.length
Smart.Code = undefined
Smart.HTML = undefined
Smart.Description = undefined
this.DBSmart.SetMap("SIMPLE" + Num, Smart)
}
}
return Smart;
}
InitHole() {
if (global.LOCAL_RUN || global.TEST_NETWORK)
this.RowHole = {}
else
this.RowHole = { "10": 1, "19": 1, "22": 1, "23": 1, "24": 1, "26": 1, "27": 1, "29": 1, "30": 1, "34": 1, "56": 1, "57": 1 }
for (var Num = 0; Num < 8; Num++)
this.RowHole[Num] = 1
}
IsHole(num) {
if (global.ALL_VIEW_ROWS)
return 0;
return this.RowHole[num];
}
};
function GetParsing(Str) {
global.LexerJS.ParseCode(Str);
var Code = global.LexerJS.stream;
for (var key in global.LexerJS.FunctionMap) {
Code += ";\nfunclist." + key + "=" + LOC_ADD_NAME + key;
}
for (var key in global.LexerJS.ExternMap) {
Code += ";\npublist." + key + "=" + LOC_ADD_NAME + key;
}
Code += "\n\
var context;\
funclist.SetContext=function(cont){context=cont;};\
";
return Code;
};
function GetSmartEvalContext(Smart) {
var EvalContext = global.DApps.Smart.DBSmart.GetMap("EVAL" + Smart.Num);
if (0)
if (Smart.Num === 26) {
const fs = require("fs");
var Path = "./dapp-smart/test-test.js";
Smart.Code = fs.readFileSync(Path, { encoding: "utf8" });
EvalContext = undefined;
}
if (!EvalContext) {
var CodeLex = GetParsing(Smart.Code);
var publist = {};
var funclist = {};
eval(CodeLex);
EvalContext = { publist: publist, funclist: funclist };
for (var key in funclist) {
Object.freeze(funclist[key]);
}
Object.freeze(funclist);
Object.freeze(publist);
global.DApps.Smart.DBSmart.SetMap("EVAL" + Smart.Num, EvalContext);
}
return EvalContext;
};
var RunContext = undefined;
global.RunSmartMethod = RunSmartMethod;
function RunSmartMethod(Block, SmartOrSmartID, Account, BlockNum?, TrNum?, PayContext?, MethodName?, Params?, bPublic?) {
var Smart = SmartOrSmartID;
if (typeof SmartOrSmartID === "number") {
Smart = global.DApps.Smart.ReadSmart(SmartOrSmartID);
if (!Smart) {
if (bPublic)
throw "Smart does not exist. Error id number: " + SmartOrSmartID;
else
return;
}
}
var EvalContext = GetSmartEvalContext(Smart);
if (!EvalContext.funclist[MethodName] || (bPublic && !EvalContext.publist[MethodName])) {
if (bPublic)
throw "Method '" + MethodName + "' not found in smart contract";
else
return;
}
var context: any = {};
if (PayContext) {
context.BlockNum = BlockNum;
context.BlockHash = global.CopyArr(Block.Hash);
context.BlockAddrHash = global.CopyArr(Block.AddrHash);
context.TrNum = TrNum;
context.Account = GET_ACCOUNT(Account);
context.Smart = GET_SMART(Smart);
context.FromNum = PayContext.FromID;
context.ToNum = PayContext.ToID;
context.Description = PayContext.Description;
if (PayContext.Value)
context.Value = { SumCOIN: PayContext.Value.SumCOIN, SumCENT: PayContext.Value.SumCENT };
}
if (BlockNum === 0) {
context.GetBlockHeader = StaticGetBlockHeader;
context.GetBlockNumDB = StaticGetBlockNumDB;
context.GetSmart = StaticGetSmart;
}
var LocalRunContext = { Block: Block, Smart: Smart, Account: Account, BlockNum: BlockNum, TrNum: TrNum, context: context };
var RetValue;
var _RunContext = RunContext;
RunContext = LocalRunContext;
EvalContext.funclist.SetContext(RunContext.context);
try {
RetValue = EvalContext.funclist[MethodName](Params);
}
catch (e) {
throw e;
}
finally {
RunContext = _RunContext;
}
return RetValue;
};
function GET_ACCOUNT(Obj) {
let Data = Obj;
var GET_PROP = {
get Num() {
return Data.Num;
}, get Currency() {
return Data.Currency;
}, get PubKey() {
return global.CopyArr(Data.PubKey);
}, get Name() {
return Data.Name;
}, get BlockNumCreate() {
return Data.BlockNumCreate;
}, get Adviser() {
return Data.Adviser;
}, get Smart() {
return Data.Smart;
}, get Value() {
return { SumCOIN: Data.Value.SumCOIN, SumCENT: Data.Value.SumCENT, OperationID: Data.Value.OperationID, Smart: Data.Value.Smart };
},
};
return GET_PROP;
};
function GET_SMART(Obj) {
let Data = Obj;
var GET_PROP = {
get Num() {
return Data.Num;
}, get Version() {
return Data.Version;
}, get TokenGenerate() {
return Data.TokenGenerate;
}, get ISIN() {
return Data.ISIN;
}, get Zip() {
return Data.Zip;
}, get BlockNum() {
return Data.BlockNum;
}, get TrNum() {
return Data.TrNum;
}, get IconBlockNum() {
return Data.IconBlockNum;
}, get IconTrNum() {
return Data.IconTrNum;
}, get ShortName() {
return Data.ShortName;
}, get Name() {
return Data.Name;
}, get Description() {
return Data.Description;
}, get Account() {
return Data.Account;
}, get AccountLength() {
return Data.AccountLength;
}, get Owner() {
return Data.Owner;
}, get Code() {
return Data.Code;
}, get HTML() {
return Data.HTML;
},
};
return GET_PROP;
};
function InitEval() {
$Math.abs = function() {
DO(6);
return Math.abs.apply(Math, arguments);
};
$Math.acos = function() {
DO(16);
return Math.acos.apply(Math, arguments);
};
$Math.acosh = function() {
DO(9);
return Math.acosh.apply(Math, arguments);
};
$Math.asin = function() {
DO(19);
return Math.asin.apply(Math, arguments);
};
$Math.asinh = function() {
DO(32);
return Math.asinh.apply(Math, arguments);
};
$Math.atan = function() {
DO(13);
return Math.atan.apply(Math, arguments);
};
$Math.atanh = function() {
DO(30);
return Math.atanh.apply(Math, arguments);
};
$Math.atan2 = function() {
DO(15);
return Math.atan2.apply(Math, arguments);
};
$Math.ceil = function() {
DO(6);
return Math.ceil.apply(Math, arguments);
};
$Math.cbrt = function() {
DO(22);
return Math.cbrt.apply(Math, arguments);
};
$Math.expm1 = function() {
DO(18);
return Math.expm1.apply(Math, arguments);
};
$Math.clz32 = function() {
DO(5);
return Math.clz32.apply(Math, arguments);
};
$Math.cos = function() {
DO(12);
return Math.cos.apply(Math, arguments);
};
$Math.cosh = function() {
DO(20);
return Math.cosh.apply(Math, arguments);
};
$Math.exp = function() {
DO(16);
return Math.exp.apply(Math, arguments);
};
$Math.floor = function() {
DO(7);
return Math.floor.apply(Math, arguments);
};
$Math.fround = function() {
DO(6);
return Math.fround.apply(Math, arguments);
};
$Math.hypot = function() {
DO(56);
return Math.hypot.apply(Math, arguments);
};
$Math.imul = function() {
DO(3);
return Math.imul.apply(Math, arguments);
};
$Math.log = function() {
DO(10);
return Math.log.apply(Math, arguments);
};
$Math.log1p = function() {
DO(23);
return Math.log1p.apply(Math, arguments);
};
$Math.log2 = function() {
DO(19);
return Math.log2.apply(Math, arguments);
};
$Math.log10 = function() {
DO(16);
return Math.log10.apply(Math, arguments);
};
$Math.max = function() {
DO(6);
return Math.max.apply(Math, arguments);
};
$Math.min = function() {
DO(6);
return Math.min.apply(Math, arguments);
};
$Math.pow = function() {
DO(40);
return Math.pow.apply(Math, arguments);
};
$Math.round = function() {
DO(7);
return Math.round.apply(Math, arguments);
};
$Math.sign = function() {
DO(5);
return Math.sign.apply(Math, arguments);
};
$Math.sin = function() {
DO(10);
return Math.sin.apply(Math, arguments);
};
$Math.sinh = function() {
DO(24);
return Math.sinh.apply(Math, arguments);
};
$Math.sqrt = function() {
DO(6);
return Math.sqrt.apply(Math, arguments);
};
$Math.tan = function() {
DO(13);
return Math.tan.apply(Math, arguments);
};
$Math.tanh = function() {
DO(24);
return Math.tanh.apply(Math, arguments);
};
$Math.trunc = function() {
DO(6);
return Math.trunc.apply(Math, arguments);
};
$Math.random = function() {
DO(1);
return 0;
};
Object.freeze($SetValue);
Object.freeze($Send);
Object.freeze($Move);
Object.freeze($Event);
Object.freeze($ReadAccount);
Object.freeze($ReadState);
Object.freeze($WriteState);
Object.freeze($GetMaxAccount);
Object.freeze($ADD);
Object.freeze($SUB);
Object.freeze($ISZERO);
Object.freeze($FLOAT_FROM_COIN);
Object.freeze($COIN_FROM_FLOAT);
Object.freeze($COIN_FROM_STRING);
Object.freeze($GetHexFromArr);
Object.freeze($GetArrFromHex);
Object.freeze($sha);
Object.freeze($isFinite);
Object.freeze($isNaN);
Object.freeze($parseFloat);
Object.freeze($parseInt);
Object.freeze($parseUint);
Object.freeze($String);
Object.freeze($Number);
Object.freeze($Boolean);
var arr = Object.getOwnPropertyNames(JSON);
for (var name of arr) {
$JSON[name] = JSON[name];
}
FreezeObjectChilds($Math);
Object.freeze($Math);
FreezeObjectChilds($JSON);
Object.freeze($JSON);
FreezeObjectChilds(Number.prototype);
FreezeObjectChilds(String.prototype);
FreezeObjectChilds(Boolean.prototype);
FreezeObjectChilds(Array.prototype);
FreezeObjectChilds(Object.prototype);
};
function FreezeObjectChilds(Value) {
var arr = Object.getOwnPropertyNames(Value);
for (var name of arr) {
Object.freeze(Value[name]);
}
};
function ChangePrototype() {
var Array_prototype_concat = Array.prototype.concat;
var Array_prototype_toString = Array.prototype.toString;
Array.prototype.concat = function() {
if (RunContext)
throw "Error Access denied: concat";
else
return Array_prototype_concat.apply(this, arguments);
};
Array.prototype.toString = function() {
if (RunContext)
throw "Error Access denied: toString";
else
return Array_prototype_toString.apply(this, arguments);
};
Array.prototype.toLocaleString = Array.prototype.toString;
Number.prototype.toLocaleString = function() {
return this.toString();
};
String.prototype.toLocaleLowerCase = String.prototype.toLowerCase;
String.prototype.toLocaleUpperCase = String.prototype.toUpperCase;
var String_prototype_localeCompare = String.prototype.localeCompare;
String.prototype.localeCompare = function() {
if (RunContext)
throw "Error Access denied: localeCompare";
else
return String_prototype_localeCompare.apply(this, arguments);
};
var String_prototype_match = String.prototype.match;
String.prototype.match = function() {
if (RunContext)
throw "Error Access denied: match";
else
return String_prototype_match.apply(this, arguments);
};
var String_prototype_repeat = String.prototype.repeat;
String.prototype.repeat = function() {
if (RunContext)
throw "Error Access denied: repeat";
else
return String_prototype_repeat.apply(this, arguments);
};
var String_prototype_search = String.prototype.search;
String.prototype.search = function() {
if (RunContext)
throw "Error Access denied: search";
else
return String_prototype_search.apply(this, arguments);
};
var String_prototype_padStart = String.prototype.padStart;
String.prototype.padStart = function() {
if (RunContext)
throw "Error Access denied: padStart";
else
return String_prototype_padStart.apply(this, arguments);
};
var String_prototype_padEnd = String.prototype.padEnd;
String.prototype.padEnd = function() {
if (RunContext)
throw "Error Access denied: padEnd";
else
return String_prototype_padEnd.apply(this, arguments);
};
String.prototype.right = function(count) {
if (this.length > count)
return this.substr(this.length - count, count);
else
return this.substr(0, this.length);
};
};
const MAX_LENGTH_STRING = 5000;
const $Math: any = {};
const $JSON: any = {};
function DO(Count) {
global.TickCounter -= Count;
if (global.TickCounter < 0)
throw new Error("Stop the execution code. The limit of ticks is over.");
};
function $SetValue(ID, CoinSum) {
DO(3000);
ID = global.ParseNum(ID);
if (!RunContext.Smart.TokenGenerate) {
throw "The smart-contract is not token generate, access to change values is denied";
}
var ToData = global.DApps.Accounts.ReadStateTR(ID);
if (!ToData) {
throw "Account does not exist.Error id number: " + ID;
}
if (ToData.Currency !== RunContext.Smart.Num) {
throw "The account currency does not belong to the smart-contract, access to change values is denied";
}
if (typeof CoinSum === "number") {
CoinSum = global.COIN_FROM_FLOAT(CoinSum);
}
if (CoinSum.SumCENT >= 1e9) {
throw "ERROR SumCENT>=1e9";
}
if (CoinSum.SumCOIN < 0 || CoinSum.SumCENT < 0) {
throw "ERROR Sum<0";
}
ToData.Value.SumCOIN = Math.trunc(CoinSum.SumCOIN);
ToData.Value.SumCENT = Math.trunc(CoinSum.SumCENT);
global.DApps.Accounts.WriteStateTR(ToData, RunContext.TrNum);
return true;
};
function $Send(ToID, CoinSum, Description) {
DO(3000);
ToID = global.ParseNum(ToID);
if (typeof CoinSum === "number")
CoinSum = global.COIN_FROM_FLOAT(CoinSum);
if (CoinSum.SumCENT >= 1e9) {
throw "ERROR SumCENT>=1e9";
}
if (CoinSum.SumCOIN < 0 || CoinSum.SumCENT < 0) {
throw "ERROR Sum<0";
}
var ToData = global.DApps.Accounts.ReadStateTR(ToID);
if (RunContext.Account.Currency !== ToData.Currency) {
throw "Different currencies";
}
global.DApps.Accounts.SendMoneyTR(RunContext.Block, RunContext.Account.Num, ToID, CoinSum, RunContext.BlockNum, RunContext.TrNum,
Description, Description, 1);
};
function $Move(FromID, ToID, CoinSum, Description) {
DO(3000);
FromID = global.ParseNum(FromID);
ToID = global.ParseNum(ToID);
var FromData = global.DApps.Accounts.ReadStateTR(FromID);
var ToData = global.DApps.Accounts.ReadStateTR(ToID);
if (FromData.Currency !== ToData.Currency) {
throw "Different currencies";
}
if (FromData.Value.Smart !== RunContext.Smart.Num) {
throw "The account smart does not belong to the smart-contract, access is denied";
}
if (typeof CoinSum === "number") {
CoinSum = global.COIN_FROM_FLOAT(CoinSum);
}
if (CoinSum.SumCENT >= 1e9) {
throw "ERROR SumCENT>=1e9";
}
if (CoinSum.SumCOIN < 0 || CoinSum.SumCENT < 0) {
throw "ERROR Sum<0";
}
CoinSum.SumCOIN = Math.trunc(CoinSum.SumCOIN);
CoinSum.SumCENT = Math.trunc(CoinSum.SumCENT);
global.DApps.Accounts.SendMoneyTR(RunContext.Block, FromID, ToID, CoinSum, RunContext.BlockNum, RunContext.TrNum, Description, Description,
1);
};
function $Event(Description) {
DO(50);
global.DApps.Accounts.DBChanges.TREvent.push({
Description: Description, Smart: RunContext.Smart.Num, Account: RunContext.Account.Num,
BlockNum: RunContext.BlockNum, TrNum: RunContext.TrNum
});
if (global.DebugEvent)
global.DebugEvent(Description);
if (global.CurTrItem) {
global.ToLogClient(Description, global.CurTrItem, false);
}
};
function $ReadAccount(ID) {
DO(900);
ID = global.ParseNum(ID);
var Account = global.DApps.Accounts.ReadStateTR(ID);
if (!Account)
throw "Error read account Num: " + ID;
return GET_ACCOUNT(Account);
};
function $ReadState(ID) {
DO(900);
ID = global.ParseNum(ID);
var Account = global.DApps.Accounts.ReadStateTR(ID);
if (!Account)
throw "Error read state account Num: " + ID;
var Smart;
if (Account.Value.Smart === RunContext.Smart.Num) {
Smart = RunContext.Smart;
}
else {
DO(100);
var Smart = global.DApps.Smart.ReadSmart(Account.Value.Smart);
if (!Smart) {
throw "Error smart ID: " + Account.Value.Smart;
}
}
var Data;
if (Smart.StateFormat)
Data = global.BufLib.GetObjectFromBuffer(Account.Value.Data, Smart.StateFormat, Smart.WorkStruct, 1);
else
Data = {};
if (typeof Data === "object")
Data.Num = ID;
return Data;
};
function $WriteState(Obj, ID) {
DO(3000);
if (ID === undefined)
ID = Obj.Num;
ID = global.ParseNum(ID);
var Account = global.DApps.Accounts.ReadStateTR(ID);
if (!Account)
throw "Error write account Num: " + ID;
var Smart = RunContext.Smart;
if (Account.Value.Smart !== Smart.Num) {
throw "The account does not belong to the smart-contract, access to change state is denied";
}
Account.Value.Data = global.BufLib.GetBufferFromObject(Obj, Smart.StateFormat, 80, Smart.WorkStruct, 1);
global.DApps.Accounts.WriteStateTR(Account, RunContext.TrNum);
};
function $GetMaxAccount() {
DO(20);
return global.DApps.Accounts.DBChanges.TRMaxAccount;
};
function $ADD(Coin, Value2) {
DO(5);
return global.ADD(Coin, Value2);
};
function $SUB(Coin, Value2) {
DO(5);
return global.SUB(Coin, Value2);
};
function $ISZERO(Coin) {
DO(5);
if (Coin.SumCOIN === 0 && Coin.SumCENT === 0)
return true;
else
return false;
};
function $FLOAT_FROM_COIN(Coin) {
DO(5);
return global.FLOAT_FROM_COIN(Coin);
};
function $COIN_FROM_FLOAT(Sum) {
DO(20);
return global.COIN_FROM_FLOAT(Sum);
};
function $COIN_FROM_STRING(Sum) {
DO(20);
return global.COIN_FROM_STRING(Sum);
};
function $require(SmartNum) {
DO(2000);
SmartNum = global.ParseNum(SmartNum);
var Smart = global.DApps.Smart.ReadSmart(SmartNum);
if (!Smart) {
throw "Smart does not exist. Error id number: " + SmartNum;
}
var EvalContext = GetSmartEvalContext(Smart);
EvalContext.funclist.SetContext(RunContext.context);
return EvalContext.publist;
};
function $GetHexFromArr(Arr) {
DO(20);
return global.GetHexFromArr(Arr);
};
function $GetArrFromHex(Str) {
DO(20);
return global.GetArrFromHex(Str);
};
function $sha(Str) {
DO(1000);
return global.shaarr(Str);
};
function $isFinite(a) {
DO(5);
return isFinite(a);
};
function $isNaN(a) {
DO(5);
return isNaN(a);
};
function $parseFloat(a) {
DO(10);
var Num = parseFloat(a);
if (!Num)
Num = 0;
if (isNaN(Num))
Num = 0;
return Num;
};
function $parseInt(a) {
DO(10);
var Num = parseInt(a);
if (!Num)
Num = 0;
if (isNaN(Num))
Num = 0;
return Num;
};
function $parseUint(a) {
DO(10);
return global.ParseNum(a);
};
function $String(a) {
DO(5);
return String(a);
};
function $Number(a) {
DO(5);
return Number(a);
};
function $Boolean(a) {
DO(5);
return Boolean(a);
};
function CHKL(Str) {
if (typeof Str === "string" && Str.length > MAX_LENGTH_STRING)
throw new Error("Invalid string length:" + Str.length);
return Str;
};
var BlockRandomInit;
var m_w = 123456789;
var m_z = 987654321;
var mask = 0xffffffff;
function MathRandom() {
DO(5);
function seed(i) {
m_w = i;
m_z = 987654321;
};
function random() {
m_z = (36969 * (m_z & 65535) + (m_z >> 16)) & mask;
m_w = (18000 * (m_w & 65535) + (m_w >> 16)) & mask;
var result = ((m_z << 16) + m_w) & mask;
result /= 4294967296;
return result + 0.5;
};
if (BlockRandomInit === RunContext.Block.BlockNum)
return random();
BlockRandomInit = RunContext.Block.BlockNum;
RunContext.Block.Hash;
return 0;
};
function StaticGetBlockHeader(BlockNum) {
DO(100);
return global.SERVER.ReadBlockHeaderDB(BlockNum);
};
function StaticGetBlockNumDB() {
return global.SERVER.GetMaxNumBlockDB();
};
function StaticGetSmart(Num) {
DO(100);
var Smart = global.DApps.Smart.ReadSmart(Num);
return GET_SMART(Smart);
};
ChangePrototype();
InitEval();
var smartApp = new SmartApp;
global.DApps.Smart = smartApp;
global.DAppByType[TYPE_TRANSACTION_SMART_CREATE] = smartApp;
global.DAppByType[global.TYPE_TRANSACTION_SMART_RUN] = smartApp;
global.DAppByType[TYPE_TRANSACTION_SMART_CHANGE] = smartApp;
export default SmartApp