Commit 17ec8479 authored by vipwzw's avatar vipwzw Committed by 33cn

fix all test

parent e23d2a79
<script src="runtime.js"></script>
<script src="test.js"></script>
<script src="game.js"></script>
<script>
//demo database function
var statedb = {}
......@@ -34,11 +34,15 @@ function getstatedb(key) {
return statedb[key]
}
function execname() {
return "user.jsvm.test"
}
function setstatedb(kvs) {
for (var i = 0; i < kvs.length; i++) {
statedb[kvs[i].key] = kvs[i].value
}
}
var ret = callcode("{}", "execlocal_hello", "{}", [])
var ret = callcode("{}", "exec_NewGame", "{}", [])
console.log(ret)
</script>
\ No newline at end of file
......@@ -282,7 +282,7 @@ func (u *js) execFrozenFunc(vm *otto.Otto) {
if err != nil {
return errReturn(vm, err)
}
receipt, err := acc.ExecFrozen(address.ExecAddress(execer), addr, amount)
receipt, err := acc.ExecFrozen(addr, address.ExecAddress(execer), amount)
if err != nil {
return errReturn(vm, err)
}
......@@ -311,7 +311,7 @@ func (u *js) execActiveFunc(vm *otto.Otto) {
if err != nil {
return errReturn(vm, err)
}
receipt, err := acc.ExecActive(address.ExecAddress(execer), addr, amount)
receipt, err := acc.ExecActive(addr, address.ExecAddress(execer), amount)
if err != nil {
return errReturn(vm, err)
}
......@@ -340,7 +340,7 @@ func (u *js) execDepositFunc(vm *otto.Otto) {
if err != nil {
return errReturn(vm, err)
}
receipt, err := acc.ExecDeposit(address.ExecAddress(execer), addr, amount)
receipt, err := acc.ExecDeposit(addr, address.ExecAddress(execer), amount)
if err != nil {
return errReturn(vm, err)
}
......
......@@ -3,14 +3,15 @@ package executor
var callcode = `
var tojson = JSON.stringify
//table warp
function table(kvc, config, defaultvalue) {
var ret = table_new(config, defaultvalue)
function Table(kvc, config, defaultvalue) {
var ret = table_new(tojson(config), tojson(defaultvalue))
if (ret.err) {
throw new Error(ret.err)
}
this.kvc = kvc
this.id = ret.id
this.config = config
this.name = config["#tablename"]
this.defaultvalue = defaultvalue
}
......@@ -18,7 +19,7 @@ function isstring(obj) {
return typeof obj === "string"
}
table.prototype.add = function(obj) {
Table.prototype.add = function(obj) {
if (!isstring(obj)) {
obj = tojson(obj)
}
......@@ -26,7 +27,35 @@ table.prototype.add = function(obj) {
return ret.err
}
table.prototype.replace = function(obj) {
Table.prototype.joinkey = function(left, right) {
return table_joinkey(left, right)
}
Table.prototype.get = function(key, row) {
return table_get(this.id, key, row)
}
Table.prototype.query = function(indexName, prefix, primaryKey, count, direction) {
if (!count) {
count = 20
}
if (!direction) {
direction = 0
}
if (!primaryKey) {
primaryKey = ""
}
if (!prefix) {
prefix = ""
}
if (!indexName) {
indexName = ""
}
var q = table_query(this.id, indexName, prefix, primaryKey, count, direction)
return tojson(q)
}
Table.prototype.replace = function(obj) {
if (!isstring(obj)) {
obj = tojson(obj)
}
......@@ -34,7 +63,7 @@ table.prototype.replace = function(obj) {
return ret.err
}
table.prototype.del = function(obj) {
Table.prototype.del = function(obj) {
if (!isstring(obj)) {
obj = tojson(obj)
}
......@@ -42,7 +71,7 @@ table.prototype.del = function(obj) {
return ret.err
}
table.prototype.save = function() {
Table.prototype.save = function() {
var ret = table_save(this.id)
if (!this.kvc) {
this.kvc.save(ret)
......@@ -50,11 +79,67 @@ table.prototype.save = function() {
return ret
}
table.prototype.close = function() {
Table.prototype.close = function() {
var ret = table_close(this.id)
return ret.err
}
function JoinTable(lefttable, righttable, index) {
this.lefttable = lefttable
this.righttable = righttable
if (this.lefttable.kvc != this.righttable.kvc) {
throw new Error("the kvc of left and right must same")
}
this.index = index
var ret = new_join_table(this.lefttable.id, this.righttable.id, index)
if (ret.err) {
throw new Error(ret.err)
}
this.id = ret.id
this.kvc = this.lefttable.kvc
}
function print(obj) {
if (typeof obj === "string") {
console.log(obj)
return
}
console.log(tojson(obj))
}
JoinTable.prototype.save = function() {
var ret = table_save(this.id)
if (this.kvc) {
this.kvc.save(ret)
}
return ret
}
JoinTable.prototype.close = function() {
table_close(this.lefttable.id)
table_close(this.righttable.id)
var ret = table_close(this.id)
return ret.err
}
JoinTable.prototype.addlogs = function(data) {
var err
for (var i = 0; i < data.length; i++) {
if (data[i].format != "json") {
continue
}
var log = JSON.parse(data[i].log)
if (log.__type__ == this.lefttable.name) {
err = this.lefttable.replace(data[i].log)
throwerr(err)
}
if (log.__type__ == this.righttable.name) {
err = this.righttable.replace(data[i].log)
throwerr(err)
}
}
}
//account warp
function account(kvc, execer, symbol) {
this.execer = execer
......@@ -64,7 +149,7 @@ function account(kvc, execer, symbol) {
account.prototype.genesisInit = function(addr, amount) {
var ret = genesis_init(this, addr, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -72,7 +157,7 @@ account.prototype.genesisInit = function(addr, amount) {
account.prototype.execGenesisInit = function(execer, addr, amount) {
var ret = genesis_init_exec(this, execer, addr, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -89,7 +174,7 @@ account.prototype.execGetBalance = function(execer, addr) {
//本合约转移资产,或者转移到其他合约,或者从其他合约取回资产
account.prototype.transfer = function(from, to, amount) {
var ret = transfer(this, from, to, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -97,7 +182,7 @@ account.prototype.transfer = function(from, to, amount) {
account.prototype.transferToExec = function(execer, from, amount) {
var ret = transfer_to_exec(this, execer, from, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -105,7 +190,7 @@ account.prototype.transferToExec = function(execer, from, amount) {
account.prototype.withdrawFromExec = function(execer, to, amount) {
var ret = withdraw(this, execer, to, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -114,7 +199,7 @@ account.prototype.withdrawFromExec = function(execer, to, amount) {
//管理其他合约的资产转移到这个合约中
account.prototype.execActive = function(execer, addr, amount) {
var ret = exec_active(this, execer, addr, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -122,7 +207,7 @@ account.prototype.execActive = function(execer, addr, amount) {
account.prototype.execFrozen = function(execer, addr, amount) {
var ret = exec_frozen(this, execer, addr, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -130,7 +215,7 @@ account.prototype.execFrozen = function(execer, addr, amount) {
account.prototype.execDeposit = function(execer, addr, amount) {
var ret = exec_deposit(this, execer, addr, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -138,7 +223,7 @@ account.prototype.execDeposit = function(execer, addr, amount) {
account.prototype.execWithdraw = function(execer, addr, amount) {
var ret = exec_withdraw(this, execer, addr, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -146,12 +231,47 @@ account.prototype.execWithdraw = function(execer, addr, amount) {
account.prototype.execTransfer = function(execer, from, to, amount) {
var ret = exec_transfer(this, execer, from, to, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
}
//from frozen -> to active
account.prototype.execTransFrozenToActive = function(execer, from, to, amount) {
var err
err = this.execActive(execer, from, amount)
if (err) {
return err
}
return this.execTransfer(execer, from, to, amount)
}
//from frozen -> to frozen
account.prototype.execTransFrozenToFrozen = function(execer, from, to, amount) {
var err
err = this.execActive(execer, from, amount)
if (err) {
return err
}
err = this.execTransfer(execer, from, to, amount)
if (err) {
return err
}
return this.execFrozen(execer, to, amount)
}
account.prototype.execTransActiveToFrozen = function(execer, from, to, amount) {
var err
err = this.execTransfer(execer, from, to, amount)
if (err) {
return err
}
return this.execFrozen(execer, to, amount)
}
COINS = 100000000
function kvcreator(dbtype) {
this.data = {}
this.kvs = []
......@@ -161,11 +281,11 @@ function kvcreator(dbtype) {
this.getloal = getlocaldb
this.list = listdb
if (dbtype == "exec" || dbtype == "init") {
this.get = this.getstatedb
this.getdb = this.getstate
} else if (dbtype == "local") {
this.get = this.getlocaldb
this.getdb = this.getlocal
} else if (dbtype == "query") {
this.get = this.getlocaldb
this.getdb = this.getlocal
} else {
throw new Error("chain33.js: dbtype error")
}
......@@ -184,8 +304,8 @@ kvcreator.prototype.get = function(k, prefix) {
if (this.data[k]) {
v = this.data[k]
} else {
var dbvalue = this.get(k, !!prefix)
if (dbvalue.err != "") {
var dbvalue = this.getdb(k, !!prefix)
if (dbvalue.err) {
return null
}
v = dbvalue.value
......@@ -213,7 +333,7 @@ kvcreator.prototype.save = function(receipt) {
kvcreator.prototype.listvalue = function(prefix, key, count, direction) {
var dbvalues = this.list(prefix, key, count, direction)
if (dbvalues.err != "") {
if (dbvalues.err) {
return []
}
var values = dbvalues.value
......@@ -247,6 +367,69 @@ kvcreator.prototype.receipt = function() {
return {kvs: this.kvs, logs: this.logs}
}
function GetExecName() {
var exec = execname()
if (exec.err) {
return ""
}
return exec.value
}
function ExecAddress(name) {
var addr = execaddress(name)
if (addr.err) {
return ""
}
console.log(addr.value)
return addr.value
}
function Sha256(data) {
var hash = sha256(data)
if (hash.err) {
return ""
}
return hash.value
}
function Exec(context) {
this.kvc = new kvcreator("exec")
this.context = context
this.name = GetExecName()
if (typeof ExecInit === "function") {
ExecInit.call(this)
}
}
Exec.prototype.txID = function() {
return this.context.height * 100000 + this.context.index
}
function ExecLocal(context, logs) {
this.kvc = new kvcreator("local")
this.context = context
this.logs = logs
this.name = GetExecName()
if (typeof ExecLocalInit === "function") {
ExecLocalInit.call(this)
}
}
function Query(context) {
this.kvc = new kvcreator("query")
this.context = context
this.name = GetExecName()
if (typeof QueryInit === "function") {
QueryInit.call(this)
}
}
function throwerr(err) {
if (err) {
throw new Error(err)
}
}
function callcode(context, f, args, loglist) {
if (f == "init") {
return Init(JSON.parse(context))
......@@ -276,7 +459,7 @@ function callcode(context, f, args, loglist) {
}
var arg = JSON.parse(args)
if (typeof runobj[funcname] != "function") {
throw new Error("chain33.js: invalid function name not found")
throw new Error("chain33.js: invalid function name not found->" + funcname)
}
return runobj[funcname](arg)
}
......@@ -285,8 +468,6 @@ function callcode(context, f, args, loglist) {
`
var jscode = `
//数据结构设计
//kvlist [{key:"key1", value:"value1"},{key:"key2", value:"value2"}]
//log 设计 {json data}
function Init(context) {
this.kvc = new kvcreator("init")
this.context = context
......@@ -295,22 +476,6 @@ function Init(context) {
return this.kvc.receipt()
}
function Exec(context) {
this.kvc = new kvcreator("exec")
this.context = context
}
function ExecLocal(context, logs) {
this.kvc = new kvcreator("local")
this.context = context
this.logs = logs
}
function Query(context) {
this.kvc = new kvcreator("query")
this.context = context
}
Exec.prototype.hello = function(args) {
this.kvc.add("args", args)
this.kvc.add("action", "exec")
......@@ -335,3 +500,245 @@ Query.prototype.hello = function(args) {
}
`
var _ = jscode
var gamecode = `
//简单的猜数字游戏
//游戏规则: 庄家出一个 0 - 10 的数字 hash(随机数 + 9) (一共的赔偿金额) NewGame()
//用户可以猜这个数字,多个用户都可以猜测。 Guess()
//开奖 CloseGame()
function Init(context) {
this.kvc = new kvcreator("init")
this.context = context
return this.kvc.receipt()
}
var MIN_WAIT_BLOCK = 2
var RAND_MAX = 10
function ExecInit() {
this.acc = new account(this.kvc, "coins", "bty")
}
Exec.prototype.NewGame = function(args) {
var game = {__type__ : "game"}
game.gameid = this.txID()
game.height = this.context.height
game.randhash = args.randhash
game.bet = args.bet
game.hash = this.context.txhash
game.obet = game.bet
game.addr = this.context.from
game.status = 1 //open
//最大值是 9000万,否则js到 int 会溢出
if (game.bet < 10 * COINS || game.bet > 10000000 * COINS) {
throwerr("bet low than 10 or hight than 10000000")
}
if (this.kvc.get(game.randhash)) { //如果randhash 已经被使用了
throwerr("dup rand hash")
}
var err = this.acc.execFrozen(this.name, this.context.from, game.bet)
throwerr(err)
this.kvc.add(game.gameid, game)
this.kvc.add(game.randhash, "ok")
this.kvc.addlog(game)
return this.kvc.receipt()
}
Exec.prototype.Guess = function(args) {
var match = {__type__ : "match"}
match.gameid = args.gameid
match.bet = args.bet
match.id = this.txID()
match.addr = this.context.from
match.hash = this.context.txhash
var game = this.kvc.get(match.gameid)
if (!game) {
throwerr("game id not found")
}
if (game.status != 1) {
throwerr("game status not open")
}
if (match.bet < 1 * COINS || match.bet > game.bet / RAND_MAX) {
throwerr("match bet litte than 1 or big than game.bet/10")
}
var err = this.acc.execFrozen(this.name, this.context.from, game.bet)
throwerr(err)
this.kvc.add(match.id, match)
this.kvc.addlog(match)
return this.kvc.receipt()
}
Exec.prototype.CloseGame = function(args) {
var local = new MatchLocalTable(this.kvc)
var game = this.kvc.get(args.id)
if (!game) {
throwerr("game id not found")
}
var matches = local.getmath(args.id)
if (!matches) {
matches = []
}
var n = -1
for (var i = 0; i < RAND_MAX; i ++) {
if (sha256(args.randstr + i) == game.randhash) {
n = i
}
}
if (n == -1) {
throwerr("err rand str")
}
//必须可以让用户可以有一个区块的竞猜时间
if (this.context.height - game.height < MIN_WAIT_BLOCK) {
throwerr("close game must wait 2 block")
}
for (var i = 0; i < matches.length; i++) {
var match = matches[i]
if (match.num == n) {
//不能随便添加辅助函数,因为可以被外界调用到,所以辅助函数都是传递 this
win(this, game, match)
} else {
fail(this, game, match)
}
}
if (game.bet > 0) {
var err = this.acc.execActive(this.name, game.addr, game.bet)
throwerr(err)
game.bet = 0
}
game.status = 2
this.kvc.add(game.gameid, game)
this.kvc.addlog(game)
return this.kvc.receipt()
}
function win(othis, game, match) {
var amount = (RAND_MAX - 1) * match.bet
if (game.bet - amount < 0) {
amount = game.bet
}
var err
if (amount > 0) {
err = this.acc.execTransFrozenToActive(othis.name, game.addr, match.addr, amount)
throwerr(err)
game.bet -= amount
}
err = othis.acc.execActive(match.addr, match.bet)
throwerr(err)
}
function fail(othis, game, match) {
var amount = match.bet
err = othis.acc.execTransFrozenToFrozen(othis.name, match.addr, game.addr, amount)
throwerr(err)
game.bet += amount
}
Exec.prototype.ForceCloseGame = function(args) {
var local = new MatchLocalTable(this.kvc)
var game = this.kvc.get(args.id)
if (!game) {
throwerr("game id not found")
}
var matches = local.getmath(args.id)
if (!matches) {
matches = []
}
if (this.context.height - game.height < 100) {
throwerr("force close game must wait 100 block")
}
for (var i = 0; i < matches.length; i++) {
var match = matches[i]
win(this.kvc, game, match)
}
if (game.bet > 0) {
var err = this.acc.execActive(this.name, game.addr, game.bet)
throwerr(err)
game.bet = 0
}
game.status = 2
this.kvc.add(game.gameid, game)
this.kvc.addlog(game)
return this.kvc.receipt()
}
ExecLocal.prototype.NewGame = function(args) {
var local = MatchGameTable(this.kvc)
local.addlogs(this.logs)
local.save()
return this.kvc.receipt()
}
ExecLocal.prototype.Guess = function(args) {
var local = MatchGameTable(this.kvc)
local.addlogs(this.logs)
local.save()
return this.kvc.receipt()
}
ExecLocal.prototype.CloseGame = function(args) {
var local = MatchGameTable(this.kvc)
local.addlogs(this.logs)
local.save()
return this.kvc.receipt()
}
ExecLocal.prototype.ForceCloseGame = function(args) {
var local = MatchGameTable(this.kvc)
local.addlogs(this.logs)
local.save()
return this.kvc.receipt()
}
Query.prototype.ListGameByAddr = function(args) {
var local = GameLocalTable(this.kvc)
return local.query("addr", args.addr, args.primaryKey, args.count, args.direction)
}
/*
game ->(1 : n) match
game.gameid -> primary
match.gameid -> fk
match.id -> primary
*/
function GameLocalTable(kvc) {
this.config = {
"#tablename" : "game",
"#primary" : "gameid",
"#db" : "localdb",
"gameid" : "%018d",
"status" : "%d",
"hash" : "%s",
"addr" : "%s",
}
this.defaultvalue = {
"gameid" : 0,
"status" : 0,
"hash" : "",
"addr" : "",
}
return new Table(kvc, this.config, this.defaultvalue)
}
function MatchLocalTable(kvc) {
this.config = {
"#tablename" : "match",
"#primary" : "id",
"#db" : "localdb",
"id" : "%018d",
"gameid" : "%018d",
"hash" : "%s",
"addr" : "%s",
}
this.defaultvalue = {
"id" : 0,
"gameid" : 0,
"hash" : "",
"addr" : "",
}
return new Table(kvc, this.config, this.defaultvalue)
}
function MatchGameTable(kvc) {
return new JoinTable(MatchLocalTable(kvc), GameLocalTable(kvc), "addr#status")
}`
var _ = gamecode
package executor_test
var jscode = `
//数据结构设计
function Init(context) {
this.kvc = new kvcreator("init")
this.context = context
this.kvc.add("action", "init")
this.kvc.add("context", this.context)
return this.kvc.receipt()
}
Exec.prototype.hello = function(args) {
this.kvc.add("args", args)
this.kvc.add("action", "exec")
this.kvc.add("context", this.context)
this.kvc.addlog({"key1": "value1"})
this.kvc.addlog({"key2": "value2"})
return this.kvc.receipt()
}
ExecLocal.prototype.hello = function(args) {
this.kvc.add("args", args)
this.kvc.add("action", "execlocal")
this.kvc.add("log", this.logs)
this.kvc.add("context", this.context)
return this.kvc.receipt()
}
//return a json string
Query.prototype.hello = function(args) {
var obj = getlocaldb("context")
return tojson(obj)
}
`
var _ = jscode
var gamecode = `
//简单的猜数字游戏
//游戏规则: 庄家出一个 0 - 10 的数字 hash(随机数 + 9) (一共的赔偿金额) NewGame()
//用户可以猜这个数字,多个用户都可以猜测。 Guess()
//开奖 CloseGame()
function Init(context) {
this.kvc = new kvcreator("init")
this.context = context
return this.kvc.receipt()
}
var MIN_WAIT_BLOCK = 2
var RAND_MAX = 10
function ExecInit() {
this.acc = new account(this.kvc, "coins", "bty")
}
Exec.prototype.NewGame = function(args) {
var game = {__type__ : "game"}
game.gameid = this.txID()
game.height = this.context.height
game.randhash = args.randhash
game.bet = args.bet
game.hash = this.context.txhash
game.obet = game.bet
game.addr = this.context.from
game.status = 1 //open
//最大值是 9000万,否则js到 int 会溢出
if (game.bet < 10 * COINS || game.bet > 10000000 * COINS) {
throwerr("bet low than 10 or hight than 10000000")
}
if (this.kvc.get(game.randhash)) { //如果randhash 已经被使用了
throwerr("dup rand hash")
}
var err = this.acc.execFrozen(this.name, this.context.from, game.bet)
throwerr(err)
this.kvc.add(game.gameid, game)
this.kvc.add(game.randhash, "ok")
this.kvc.addlog(game)
return this.kvc.receipt()
}
Exec.prototype.Guess = function(args) {
var match = {__type__ : "match"}
match.gameid = args.gameid
match.bet = args.bet
match.id = this.txID()
match.addr = this.context.from
match.hash = this.context.txhash
var game = this.kvc.get(match.gameid)
if (!game) {
throwerr("game id not found")
}
if (game.status != 1) {
throwerr("game status not open")
}
if (match.bet < 1 * COINS || match.bet > game.bet / RAND_MAX) {
throwerr("match bet litte than 1 or big than game.bet/10")
}
var err = this.acc.execFrozen(this.name, this.context.from, game.bet)
throwerr(err)
this.kvc.add(match.id, match)
this.kvc.addlog(match)
return this.kvc.receipt()
}
Exec.prototype.CloseGame = function(args) {
var local = new MatchLocalTable(this.kvc)
var game = this.kvc.get(args.id)
if (!game) {
throwerr("game id not found")
}
var matches = local.getmath(args.id)
if (!matches) {
matches = []
}
var n = -1
for (var i = 0; i < RAND_MAX; i ++) {
if (sha256(args.randstr + i) == game.randhash) {
n = i
}
}
if (n == -1) {
throwerr("err rand str")
}
//必须可以让用户可以有一个区块的竞猜时间
if (this.context.height - game.height < MIN_WAIT_BLOCK) {
throwerr("close game must wait 2 block")
}
for (var i = 0; i < matches.length; i++) {
var match = matches[i]
if (match.num == n) {
//不能随便添加辅助函数,因为可以被外界调用到,所以辅助函数都是传递 this
win(this, game, match)
} else {
fail(this, game, match)
}
}
if (game.bet > 0) {
var err = this.acc.execActive(this.name, game.addr, game.bet)
throwerr(err)
game.bet = 0
}
game.status = 2
this.kvc.add(game.gameid, game)
this.kvc.addlog(game)
return this.kvc.receipt()
}
function win(othis, game, match) {
var amount = (RAND_MAX - 1) * match.bet
if (game.bet - amount < 0) {
amount = game.bet
}
var err
if (amount > 0) {
err = this.acc.execTransFrozenToActive(othis.name, game.addr, match.addr, amount)
throwerr(err)
game.bet -= amount
}
err = othis.acc.execActive(match.addr, match.bet)
throwerr(err)
}
function fail(othis, game, match) {
var amount = match.bet
err = othis.acc.execTransFrozenToFrozen(othis.name, match.addr, game.addr, amount)
throwerr(err)
game.bet += amount
}
Exec.prototype.ForceCloseGame = function(args) {
var local = new MatchLocalTable(this.kvc)
var game = this.kvc.get(args.id)
if (!game) {
throwerr("game id not found")
}
var matches = local.getmath(args.id)
if (!matches) {
matches = []
}
if (this.context.height - game.height < 100) {
throwerr("force close game must wait 100 block")
}
for (var i = 0; i < matches.length; i++) {
var match = matches[i]
win(this.kvc, game, match)
}
if (game.bet > 0) {
var err = this.acc.execActive(this.name, game.addr, game.bet)
throwerr(err)
game.bet = 0
}
game.status = 2
this.kvc.add(game.gameid, game)
this.kvc.addlog(game)
return this.kvc.receipt()
}
ExecLocal.prototype.NewGame = function(args) {
var local = MatchGameTable(this.kvc)
local.addlogs(this.logs)
local.save()
return this.kvc.receipt()
}
ExecLocal.prototype.Guess = function(args) {
var local = MatchGameTable(this.kvc)
local.addlogs(this.logs)
local.save()
return this.kvc.receipt()
}
ExecLocal.prototype.CloseGame = function(args) {
var local = MatchGameTable(this.kvc)
local.addlogs(this.logs)
local.save()
return this.kvc.receipt()
}
ExecLocal.prototype.ForceCloseGame = function(args) {
var local = MatchGameTable(this.kvc)
local.addlogs(this.logs)
local.save()
return this.kvc.receipt()
}
Query.prototype.ListGameByAddr = function(args) {
var local = GameLocalTable(this.kvc)
return local.query("addr", args.addr, args.primaryKey, args.count, args.direction)
}
/*
game ->(1 : n) match
game.gameid -> primary
match.gameid -> fk
match.id -> primary
*/
function GameLocalTable(kvc) {
this.config = {
"#tablename" : "game",
"#primary" : "gameid",
"#db" : "localdb",
"gameid" : "%018d",
"status" : "%d",
"hash" : "%s",
"addr" : "%s",
}
this.defaultvalue = {
"gameid" : 0,
"status" : 0,
"hash" : "",
"addr" : "",
}
return new Table(kvc, this.config, this.defaultvalue)
}
function MatchLocalTable(kvc) {
this.config = {
"#tablename" : "match",
"#primary" : "id",
"#db" : "localdb",
"id" : "%018d",
"gameid" : "%018d",
"hash" : "%s",
"addr" : "%s",
}
this.defaultvalue = {
"id" : 0,
"gameid" : 0,
"hash" : "",
"addr" : "",
}
return new Table(kvc, this.config, this.defaultvalue)
}
function MatchGameTable(kvc) {
return new JoinTable(MatchLocalTable(kvc), GameLocalTable(kvc), "addr#status")
}`
var _ = gamecode
package executor
import (
"fmt"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
ptypes "github.com/33cn/plugin/plugin/dapp/js/types"
......@@ -28,5 +30,8 @@ func (c *js) ExecLocal_Call(payload *jsproto.Call, tx *types.Transaction, receip
kvc.AddRollbackKV()
r := &types.LocalDBSet{}
r.KV = kvc.KVList()
for i := 0; i < len(r.KV); i++ {
fmt.Println(string(r.KV[i].Key))
}
return r, nil
}
......@@ -11,17 +11,17 @@ function Init(context) {
var MIN_WAIT_BLOCK = 2
var RAND_MAX = 10
function ExecInit(execthis) {
execthis.acc = new account(this.kvc, "coins", "bty")
function ExecInit() {
this.acc = new account(this.kvc, "coins", "bty")
}
Exec.prototype.NewGame = function(args) {
var game = {__type__ : "game"}
game.id = this.context.txhash
game.index = this.txID()
game.gameid = this.txID()
game.height = this.context.height
game.randhash = args.hash
game.randhash = args.randhash
game.bet = args.bet
game.hash = this.context.txhash
game.obet = game.bet
game.addr = this.context.from
game.status = 1 //open
......@@ -29,9 +29,13 @@ Exec.prototype.NewGame = function(args) {
if (game.bet < 10 * COINS || game.bet > 10000000 * COINS) {
throwerr("bet low than 10 or hight than 10000000")
}
if (this.kvc.get(game.randhash)) { //如果randhash 已经被使用了
throwerr("dup rand hash")
}
var err = this.acc.execFrozen(this.name, this.context.from, game.bet)
throwerr(err)
this.kvc.add(game.id, game)
this.kvc.add(game.gameid, game)
this.kvc.add(game.randhash, "ok")
this.kvc.addlog(game)
return this.kvc.receipt()
}
......@@ -42,6 +46,7 @@ Exec.prototype.Guess = function(args) {
match.bet = args.bet
match.id = this.txID()
match.addr = this.context.from
match.hash = this.context.txhash
var game = this.kvc.get(match.gameid)
if (!game) {
throwerr("game id not found")
......@@ -97,29 +102,29 @@ Exec.prototype.CloseGame = function(args) {
game.bet = 0
}
game.status = 2
this.kvc.add(game.id, game)
this.kvc.add(game.gameid, game)
this.kvc.addlog(game)
return this.kvc.receipt()
}
function win(this, game, match) {
function win(othis, game, match) {
var amount = (RAND_MAX - 1) * match.bet
if (game.bet - amount < 0) {
amount = game.bet
}
var err
if (amount > 0) {
err = this.acc.execTransFrozenToActive(this.name, game.addr, match.addr, amount)
err = this.acc.execTransFrozenToActive(othis.name, game.addr, match.addr, amount)
throwerr(err)
game.bet -= amount
}
err = this.acc.execActive(match.addr, match.bet)
err = othis.acc.execActive(match.addr, match.bet)
throwerr(err)
}
function fail(this, game, match) {
function fail(othis, game, match) {
var amount = match.bet
err = this.acc.execTransFrozenToFrozen(this.name, match.addr, game.addr, amount)
err = othis.acc.execTransFrozenToFrozen(othis.name, match.addr, game.addr, amount)
throwerr(err)
game.bet += amount
}
......@@ -147,47 +152,47 @@ Exec.prototype.ForceCloseGame = function(args) {
game.bet = 0
}
game.status = 2
this.kvc.add(game.id, game)
this.kvc.add(game.gameid, game)
this.kvc.addlog(game)
return this.kvc.receipt()
}
ExecLocal.prototype.NewGame = function(args) {
var local = new MatchGameTable(this.kvc)
local.add(this.logs)
local.table.save()
var local = MatchGameTable(this.kvc)
local.addlogs(this.logs)
local.save()
return this.kvc.receipt()
}
ExecLocal.prototype.Guess = function(args) {
var local = new MatchGameTable(this.kvc)
local.add(this.logs)
local.table.save()
var local = MatchGameTable(this.kvc)
local.addlogs(this.logs)
local.save()
return this.kvc.receipt()
}
ExecLocal.prototype.CloseGame = function(args) {
var local = new MatchGameTable(this.kvc)
local.add(this.logs)
local.table.save()
var local = MatchGameTable(this.kvc)
local.addlogs(this.logs)
local.save()
return this.kvc.receipt()
}
ExecLocal.prototype.ForceCloseGame = function(args) {
var local = new GameLocalTable(this.kvc)
local.add(this.logs)
local.table.save()
var local = MatchGameTable(this.kvc)
local.addlogs(this.logs)
local.save()
return this.kvc.receipt()
}
Query.prototype.ListGameByAddr = function(args) {
var local = new GameLocalTable(this.kvc)
return local.query(args)
var local = GameLocalTable(this.kvc)
return local.query("addr", args.addr, args.primaryKey, args.count, args.direction)
}
/*
game ->(1 : n) match
game.id -> primary
game.gameid -> primary
match.gameid -> fk
match.id -> primary
......@@ -195,19 +200,20 @@ match.id -> primary
function GameLocalTable(kvc) {
this.config = {
"#tablename" : "game",
"#primary" : "id",
"#primary" : "gameid",
"#db" : "localdb",
"id" : "%018d",
"gameid" : "%018d",
"status" : "%d",
"hash" : "%s",
"addr" : "%s",
}
this.defaultvalue = {
"id" : "0",
"gameid" : 0,
"status" : 0,
"hash" : "",
"addr" : "",
}
this.kvc = kvc
this.table = new Table(this.kvc, this.config, this.defaultvalue)
return new Table(kvc, this.config, this.defaultvalue)
}
function MatchLocalTable(kvc) {
......@@ -216,29 +222,19 @@ function MatchLocalTable(kvc) {
"#primary" : "id",
"#db" : "localdb",
"id" : "%018d",
"gameid" : "%s",
"gameid" : "%018d",
"hash" : "%s",
"addr" : "%s",
}
this.defaultvalue = {
"id" : 0,
"gameid" : 0,
"hash" : "",
"addr" : "",
}
this.kvc = kvc
this.table = new Table(this.kvc, this.config, this.defaultvalue)
return new Table(kvc, this.config, this.defaultvalue)
}
function MatchGameTable(kvc) {
this.left = MatchLocalTable(kvc)
this.right = GameLocalTable(kvc)
this.table = new JoinTable(left, right, "addr#status")
}
MatchGameTable.prototype.add = function(data) {
if (data.__type__ == "match") {
this.left.table.replace(data)
}
if (data.__type__ == "game") {
this.right.table.replace(data)
}
return new JoinTable(MatchLocalTable(kvc), GameLocalTable(kvc), "addr#status")
}
\ No newline at end of file
......@@ -8,4 +8,19 @@
cat "test.js"
printf '`\n'
printf 'var _ = jscode\n'
printf 'var gamecode = `\n'
cat "game.js"
printf '`\n'
printf 'var _ = gamecode\n'
} >const.go
{
printf 'package executor_test\n\nvar jscode = `\n'
cat "test.js"
printf '`\n'
printf 'var _ = jscode\n'
printf 'var gamecode = `\n'
cat "game.js"
printf '`\n'
printf 'var _ = gamecode\n'
} >const_test.go
\ No newline at end of file
......@@ -3,7 +3,7 @@ package executor
import (
"bytes"
"encoding/json"
"fmt"
"sync"
"sync/atomic"
"github.com/33cn/chain33/common"
......@@ -28,7 +28,6 @@ func init() {
panic(err)
}
execaddressFunc(basevm)
registerTableFunc(basevm)
sha256Func(basevm)
}
......@@ -49,7 +48,9 @@ func Init(name string, sub []byte) {
type js struct {
drivers.DriverBase
prefix []byte
prefix []byte
globalTableHandle sync.Map
globalHanldeID int64
}
func newjs() drivers.Driver {
......@@ -224,7 +225,7 @@ func (u *js) localdbFunc(vm *otto.Otto, name string) {
func (u *js) execnameFunc(vm *otto.Otto, name string) {
vm.Set("execname", func(call otto.FunctionCall) otto.Value {
return okReturn(vm, types.ExecName("user.js."+name))
return okReturn(vm, types.ExecName("user."+ptypes.JsX+"."+name))
})
}
......@@ -281,7 +282,7 @@ func (u *js) createVM(name string, tx *types.Transaction, index int) (*otto.Otto
u.listdbFunc(vm, name)
u.execnameFunc(vm, name)
u.registerAccountFunc(vm)
u.newTableFunc(vm, name)
u.registerTableFunc(vm, name)
return vm, nil
}
......@@ -360,26 +361,28 @@ func (u *js) Allow(tx *types.Transaction, index int) error {
return types.ErrNotAllow
}
func createKVObject(vm *otto.Otto, kvs []*types.KeyValue) otto.Value {
obj := newObjectString(vm, "([])")
func createKVObject(vm *otto.Otto, kvs []*types.KeyValue) []interface{} {
data := make([]interface{}, len(kvs))
for i := 0; i < len(kvs); i++ {
item := newObject(vm).setValue("key", string(kvs[i].Key))
item.setValue("value", string(kvs[i].Value))
item.setValue("prefix", true)
obj.setValue(fmt.Sprint(i), item)
item := make(map[string]interface{})
item["key"] = string(kvs[i].Key)
item["value"] = string(kvs[i].Value)
item["prefix"] = true
data[i] = item
}
return obj.value()
return data
}
func createLogsObject(vm *otto.Otto, logs []*types.ReceiptLog) otto.Value {
obj := newObjectString(vm, "([])")
func createLogsObject(vm *otto.Otto, logs []*types.ReceiptLog) []interface{} {
data := make([]interface{}, len(logs))
for i := 0; i < len(logs); i++ {
item := newObject(vm).setValue("ty", logs[i].Ty)
item.setValue("log", string(logs[i].Log))
item.setValue("format", "proto")
obj.setValue(fmt.Sprint(i), item)
item := make(map[string]interface{})
item["ty"] = logs[i].Ty
item["log"] = string(logs[i].Log)
item["format"] = "proto"
data[i] = item
}
return obj.value()
return data
}
func accountReturn(vm *otto.Otto, acc *types.Account) otto.Value {
......
......@@ -22,12 +22,12 @@ func init() {
Init(ptypes.JsX, nil)
}
func initExec(ldb db.DB, kvdb db.KVDB, t assert.TestingT) *js {
func initExec(ldb db.DB, kvdb db.KVDB, code string, t assert.TestingT) *js {
e := newjs().(*js)
e.SetEnv(1, time.Now().Unix(), 1)
e.SetLocalDB(kvdb)
e.SetStateDB(kvdb)
c, tx := createCodeTx("test", jscode)
c, tx := createCodeTx("test", code)
receipt, err := e.Exec_Create(c, tx, 0)
assert.Nil(t, err)
util.SaveKVList(ldb, receipt.KV)
......@@ -54,7 +54,7 @@ func callCodeTx(name, f, args string) (*jsproto.Call, *types.Transaction) {
func TestCallcode(t *testing.T) {
dir, ldb, kvdb := util.CreateTestDB()
defer util.CloseTestDB(dir, ldb)
e := initExec(ldb, kvdb, t)
e := initExec(ldb, kvdb, jscode, t)
call, tx := callCodeTx("test", "hello", `{"hello":"world"}`)
receipt, err := e.Exec_Call(call, tx, 0)
......@@ -107,7 +107,7 @@ func TestCallcode(t *testing.T) {
func TestCallError(t *testing.T) {
dir, ldb, kvdb := util.CreateTestDB()
defer util.CloseTestDB(dir, ldb)
e := initExec(ldb, kvdb, t)
e := initExec(ldb, kvdb, jscode, t)
//test call error(invalid json input)
call, tx := callCodeTx("test", "hello", `{hello":"world"}`)
_, err := e.callVM("exec", call, tx, 0, nil)
......@@ -132,7 +132,7 @@ func TestCallError(t *testing.T) {
func TestBigInt(t *testing.T) {
dir, ldb, kvdb := util.CreateTestDB()
defer util.CloseTestDB(dir, ldb)
e := initExec(ldb, kvdb, t)
e := initExec(ldb, kvdb, jscode, t)
//test call error(invalid json input)
s := fmt.Sprintf(`{"balance":%d,"balance1":%d,"balance2":%d,"balance3":%d}`, math.MaxInt64, math.MinInt64, 9007199254740990, -9007199254740990)
call, tx := callCodeTx("test", "hello", s)
......@@ -146,7 +146,7 @@ func TestBigInt(t *testing.T) {
func BenchmarkBigInt(b *testing.B) {
dir, ldb, kvdb := util.CreateTestDB()
defer util.CloseTestDB(dir, ldb)
e := initExec(ldb, kvdb, b)
e := initExec(ldb, kvdb, jscode, b)
//test call error(invalid json input)
s := fmt.Sprintf(`{"balance":%d,"balance1":%d,"balance2":%d,"balance3":%d}`, math.MaxInt64, math.MinInt64, 9007199254740990, -9007199254740990)
call, tx := callCodeTx("test", "hello", s)
......@@ -184,7 +184,7 @@ func TestCalcLocalPrefix(t *testing.T) {
func TestCacheMemUsage(t *testing.T) {
dir, ldb, kvdb := util.CreateTestDB()
defer util.CloseTestDB(dir, ldb)
e := initExec(ldb, kvdb, t)
e := initExec(ldb, kvdb, jscode, t)
vm, err := e.createVM("test", nil, 0)
assert.Nil(t, err)
vms := make([]*otto.Otto, 1024)
......
......@@ -4,10 +4,13 @@ import (
"fmt"
"github.com/33cn/chain33/types"
ptypes "github.com/33cn/plugin/plugin/dapp/js/types"
"github.com/33cn/plugin/plugin/dapp/js/types/jsproto"
)
func (c *js) Query_Query(payload *jsproto.Call) (types.Message, error) {
execer := types.ExecName("user." + ptypes.JsX + "." + payload.Name)
c.prefix = calcLocalPrefix([]byte(execer))
jsvalue, err := c.callVM("query", payload, nil, 0, nil)
if err != nil {
fmt.Println("query", err)
......
package executor_test
import (
"fmt"
"math/rand"
"testing"
"time"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/address"
rpctypes "github.com/33cn/chain33/rpc/types"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util/testnode"
......@@ -14,6 +19,10 @@ import (
_ "github.com/33cn/plugin/plugin"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
func TestJsVM(t *testing.T) {
mocker := testnode.New("--free--", nil)
defer mocker.Close()
......@@ -75,53 +84,95 @@ func TestJsVM(t *testing.T) {
t.Log(queryresult.Data)
}
var jscode = `
//数据结构设计
//kvlist [{key:"key1", value:"value1"},{key:"key2", value:"value2"}]
//log 设计 {json data}
function Init(context) {
this.kvc = new kvcreator("init")
this.context = context
this.kvc.add("action", "init")
this.kvc.add("context", this.context)
return this.kvc.receipt()
}
function Exec(context) {
this.kvc = new kvcreator("exec")
this.context = context
}
function ExecLocal(context, logs) {
this.kvc = new kvcreator("local")
this.context = context
this.logs = logs
}
function Query(context) {
this.kvc = new kvcreator("query")
this.context = context
}
Exec.prototype.hello = function(args) {
this.kvc.add("args", args)
this.kvc.add("action", "exec")
this.kvc.add("context", this.context)
this.kvc.addlog({"key1": "value1"})
this.kvc.addlog({"key2": "value2"})
return this.kvc.receipt()
}
func TestJsGame(t *testing.T) {
contractName := "test1"
mocker := testnode.New("--free--", nil)
defer mocker.Close()
mocker.Listen()
err := mocker.SendHot()
assert.Nil(t, err)
//开始部署合约, 测试阶段任何人都可以部署合约
//后期需要加上权限控制
//1. 部署合约
create := &jsproto.Create{
Code: gamecode,
Name: contractName,
}
req := &rpctypes.CreateTxIn{
Execer: ptypes.JsX,
ActionName: "Create",
Payload: types.MustPBToJSON(create),
}
var txhex string
err = mocker.GetJSONC().Call("Chain33.CreateTransaction", req, &txhex)
assert.Nil(t, err)
hash, err := mocker.SendAndSign(mocker.GetHotKey(), txhex)
assert.Nil(t, err)
txinfo, err := mocker.WaitTx(hash)
assert.Nil(t, err)
assert.Equal(t, txinfo.Receipt.Ty, int32(2))
block := mocker.GetLastBlock()
balance := mocker.GetAccount(block.StateHash, mocker.GetHotAddress()).Balance
assert.Equal(t, balance, 10000*types.Coin)
//2.1 充值到合约
reqtx := &rpctypes.CreateTx{
To: address.ExecAddress("user.jsvm." + contractName),
Amount: 100 * types.Coin,
Note: "12312",
IsWithdraw: false,
IsToken: false,
TokenSymbol: "",
ExecName: "user.jsvm." + contractName,
}
err = mocker.GetJSONC().Call("Chain33.CreateRawTransaction", reqtx, &txhex)
assert.Nil(t, err)
hash, err = mocker.SendAndSign(mocker.GetHotKey(), txhex)
assert.Nil(t, err)
txinfo, err = mocker.WaitTx(hash)
assert.Nil(t, err)
assert.Equal(t, txinfo.Receipt.Ty, int32(2))
block = mocker.GetLastBlock()
balance = mocker.GetExecAccount(block.StateHash, "user.jsvm."+contractName, mocker.GetHotAddress()).Balance
assert.Equal(t, 100*types.Coin, balance)
//2.2 调用 hello 函数(随机数,用nonce)
privhash := common.Sha256(mocker.GetHotKey().Bytes())
nonce := rand.Int63()
num := rand.Int63() % 10
realhash := common.Sha256([]byte(string(privhash) + ":" + fmt.Sprint(nonce)))
myhash := common.ToHex(common.Sha256([]byte(string(realhash) + fmt.Sprint(num))))
ExecLocal.prototype.hello = function(args) {
this.kvc.add("args", args)
this.kvc.add("action", "execlocal")
this.kvc.add("log", this.logs)
this.kvc.add("context", this.context)
return this.kvc.receipt()
}
call := &jsproto.Call{
Funcname: "NewGame",
Name: contractName,
Args: fmt.Sprintf(`{"bet": %d, "randhash" : "%s"}`, 100*types.Coin, myhash),
}
req = &rpctypes.CreateTxIn{
Execer: "user." + ptypes.JsX + "." + contractName,
ActionName: "Call",
Payload: types.MustPBToJSON(call),
}
err = mocker.GetJSONC().Call("Chain33.CreateTransaction", req, &txhex)
assert.Nil(t, err)
t.Log(mocker.GetHotAddress())
hash, err = mocker.SendAndSignNonce(mocker.GetHotKey(), txhex, nonce)
assert.Nil(t, err)
txinfo, err = mocker.WaitTx(hash)
assert.Nil(t, err)
assert.Equal(t, txinfo.Receipt.Ty, int32(2))
//return a json string
Query.prototype.hello = function(args) {
return tojson({hello:"wzw"})
//3. query 函数查询
call = &jsproto.Call{
Funcname: "ListGameByAddr",
Name: contractName,
Args: fmt.Sprintf(`{"addr":"%s", "count" : 20}`, txinfo.Tx.From),
}
query := &rpctypes.Query4Jrpc{
Execer: "user." + ptypes.JsX + "." + contractName,
FuncName: "Query",
Payload: types.MustPBToJSON(call),
}
var queryresult jsproto.QueryResult
err = mocker.GetJSONC().Call("Chain33.Query", query, &queryresult)
assert.Nil(t, err)
t.Log(queryresult.Data)
}
`
var tojson = JSON.stringify
//table warp
function table(kvc, config, defaultvalue) {
var ret = table_new(config, defaultvalue)
function Table(kvc, config, defaultvalue) {
var ret = table_new(tojson(config), tojson(defaultvalue))
if (ret.err) {
throw new Error(ret.err)
}
this.kvc = kvc
this.id = ret.id
this.config = config
this.name = config["#tablename"]
this.defaultvalue = defaultvalue
}
......@@ -15,7 +16,7 @@ function isstring(obj) {
return typeof obj === "string"
}
table.prototype.add = function(obj) {
Table.prototype.add = function(obj) {
if (!isstring(obj)) {
obj = tojson(obj)
}
......@@ -23,7 +24,35 @@ table.prototype.add = function(obj) {
return ret.err
}
table.prototype.replace = function(obj) {
Table.prototype.joinkey = function(left, right) {
return table_joinkey(left, right)
}
Table.prototype.get = function(key, row) {
return table_get(this.id, key, row)
}
Table.prototype.query = function(indexName, prefix, primaryKey, count, direction) {
if (!count) {
count = 20
}
if (!direction) {
direction = 0
}
if (!primaryKey) {
primaryKey = ""
}
if (!prefix) {
prefix = ""
}
if (!indexName) {
indexName = ""
}
var q = table_query(this.id, indexName, prefix, primaryKey, count, direction)
return tojson(q)
}
Table.prototype.replace = function(obj) {
if (!isstring(obj)) {
obj = tojson(obj)
}
......@@ -31,7 +60,7 @@ table.prototype.replace = function(obj) {
return ret.err
}
table.prototype.del = function(obj) {
Table.prototype.del = function(obj) {
if (!isstring(obj)) {
obj = tojson(obj)
}
......@@ -39,7 +68,7 @@ table.prototype.del = function(obj) {
return ret.err
}
table.prototype.save = function() {
Table.prototype.save = function() {
var ret = table_save(this.id)
if (!this.kvc) {
this.kvc.save(ret)
......@@ -47,17 +76,17 @@ table.prototype.save = function() {
return ret
}
table.prototype.close = function() {
Table.prototype.close = function() {
var ret = table_close(this.id)
return ret.err
}
function JoinTable(lefttable, righttable, index) {
this.lefttable = lefttable
this.righttable = righttable
if (this.lefttable.kvc != this.righttable.kvc) {
throw new Error("the kvc of left and right must same")
}
this.lefttable = lefttable
this.righttable = righttable
this.index = index
var ret = new_join_table(this.lefttable.id, this.righttable.id, index)
if (ret.err) {
......@@ -67,9 +96,17 @@ function JoinTable(lefttable, righttable, index) {
this.kvc = this.lefttable.kvc
}
JoinTable.prototype.Save = function() {
function print(obj) {
if (typeof obj === "string") {
console.log(obj)
return
}
console.log(tojson(obj))
}
JoinTable.prototype.save = function() {
var ret = table_save(this.id)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret
......@@ -82,6 +119,24 @@ JoinTable.prototype.close = function() {
return ret.err
}
JoinTable.prototype.addlogs = function(data) {
var err
for (var i = 0; i < data.length; i++) {
if (data[i].format != "json") {
continue
}
var log = JSON.parse(data[i].log)
if (log.__type__ == this.lefttable.name) {
err = this.lefttable.replace(data[i].log)
throwerr(err)
}
if (log.__type__ == this.righttable.name) {
err = this.righttable.replace(data[i].log)
throwerr(err)
}
}
}
//account warp
function account(kvc, execer, symbol) {
this.execer = execer
......@@ -91,7 +146,7 @@ function account(kvc, execer, symbol) {
account.prototype.genesisInit = function(addr, amount) {
var ret = genesis_init(this, addr, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -99,7 +154,7 @@ account.prototype.genesisInit = function(addr, amount) {
account.prototype.execGenesisInit = function(execer, addr, amount) {
var ret = genesis_init_exec(this, execer, addr, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -116,7 +171,7 @@ account.prototype.execGetBalance = function(execer, addr) {
//本合约转移资产,或者转移到其他合约,或者从其他合约取回资产
account.prototype.transfer = function(from, to, amount) {
var ret = transfer(this, from, to, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -124,7 +179,7 @@ account.prototype.transfer = function(from, to, amount) {
account.prototype.transferToExec = function(execer, from, amount) {
var ret = transfer_to_exec(this, execer, from, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -132,7 +187,7 @@ account.prototype.transferToExec = function(execer, from, amount) {
account.prototype.withdrawFromExec = function(execer, to, amount) {
var ret = withdraw(this, execer, to, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -141,7 +196,7 @@ account.prototype.withdrawFromExec = function(execer, to, amount) {
//管理其他合约的资产转移到这个合约中
account.prototype.execActive = function(execer, addr, amount) {
var ret = exec_active(this, execer, addr, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -149,7 +204,7 @@ account.prototype.execActive = function(execer, addr, amount) {
account.prototype.execFrozen = function(execer, addr, amount) {
var ret = exec_frozen(this, execer, addr, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -157,7 +212,7 @@ account.prototype.execFrozen = function(execer, addr, amount) {
account.prototype.execDeposit = function(execer, addr, amount) {
var ret = exec_deposit(this, execer, addr, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -165,7 +220,7 @@ account.prototype.execDeposit = function(execer, addr, amount) {
account.prototype.execWithdraw = function(execer, addr, amount) {
var ret = exec_withdraw(this, execer, addr, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -173,7 +228,7 @@ account.prototype.execWithdraw = function(execer, addr, amount) {
account.prototype.execTransfer = function(execer, from, to, amount) {
var ret = exec_transfer(this, execer, from, to, amount)
if (!this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
}
return ret.err
......@@ -203,6 +258,15 @@ account.prototype.execTransFrozenToFrozen = function(execer, from, to, amount) {
return this.execFrozen(execer, to, amount)
}
account.prototype.execTransActiveToFrozen = function(execer, from, to, amount) {
var err
err = this.execTransfer(execer, from, to, amount)
if (err) {
return err
}
return this.execFrozen(execer, to, amount)
}
COINS = 100000000
function kvcreator(dbtype) {
......@@ -214,11 +278,11 @@ function kvcreator(dbtype) {
this.getloal = getlocaldb
this.list = listdb
if (dbtype == "exec" || dbtype == "init") {
this.get = this.getstatedb
this.getdb = this.getstate
} else if (dbtype == "local") {
this.get = this.getlocaldb
this.getdb = this.getlocal
} else if (dbtype == "query") {
this.get = this.getlocaldb
this.getdb = this.getlocal
} else {
throw new Error("chain33.js: dbtype error")
}
......@@ -237,7 +301,7 @@ kvcreator.prototype.get = function(k, prefix) {
if (this.data[k]) {
v = this.data[k]
} else {
var dbvalue = this.get(k, !!prefix)
var dbvalue = this.getdb(k, !!prefix)
if (dbvalue.err) {
return null
}
......@@ -300,35 +364,60 @@ kvcreator.prototype.receipt = function() {
return {kvs: this.kvs, logs: this.logs}
}
function GetExecName() {
var exec = execname()
if (exec.err) {
return ""
}
return exec.value
}
function ExecAddress(name) {
var addr = execaddress(name)
if (addr.err) {
return ""
}
console.log(addr.value)
return addr.value
}
function Sha256(data) {
var hash = sha256(data)
if (hash.err) {
return ""
}
return hash.value
}
function Exec(context) {
this.kvc = new kvcreator("exec")
this.context = context
this.name = execname()
if (typeof ExecInit == "function") {
ExecInit(this)
this.name = GetExecName()
if (typeof ExecInit === "function") {
ExecInit.call(this)
}
}
Exec.prototype.txID = function() {
return this.context.height * 100000 + this.index
return this.context.height * 100000 + this.context.index
}
function ExecLocal(context, logs) {
this.kvc = new kvcreator("local")
this.context = context
this.logs = logs
this.name = execname()
if (typeof ExecLocalInit == "function") {
ExecLocalInit(this)
this.name = GetExecName()
if (typeof ExecLocalInit === "function") {
ExecLocalInit.call(this)
}
}
function Query(context) {
this.kvc = new kvcreator("query")
this.context = context
this.name = execname()
if (typeof QueryInit == "function") {
QueryInit(this)
this.name = GetExecName()
if (typeof QueryInit === "function") {
QueryInit.call(this)
}
}
......@@ -367,7 +456,7 @@ function callcode(context, f, args, loglist) {
}
var arg = JSON.parse(args)
if (typeof runobj[funcname] != "function") {
throw new Error("chain33.js: invalid function name not found")
throw new Error("chain33.js: invalid function name not found->" + funcname)
}
return runobj[funcname](arg)
}
......
package executor
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"regexp"
"strings"
"sync"
"sync/atomic"
"github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/db/table"
......@@ -35,22 +35,11 @@ import (
"index2" : "",
}
*/
var globalTableHandle sync.Map
var globalHanldeID int64
//NewTable 创建一个新的表格, 返回handle
func (u *js) newTable(name, config, defaultvalue string) (id int64, err error) {
for {
id = atomic.AddInt64(&globalHanldeID, 1) % maxjsint
if _, ok := globalTableHandle.Load(id); ok {
continue
}
if id < 0 {
atomic.StoreInt64(&globalHanldeID, 0)
continue
}
break
}
u.globalHanldeID++
id = u.globalHanldeID
row, err := NewJSONRow(config, defaultvalue)
if err != nil {
return 0, err
......@@ -74,7 +63,7 @@ func (u *js) newTable(name, config, defaultvalue string) (id int64, err error) {
indexs = append(indexs, k)
}
opt := &table.Option{
Prefix: string(prefix),
Prefix: strings.Trim(string(prefix), "-"),
Name: row.config["#tablename"],
Primary: row.config["#primary"],
Index: indexs,
......@@ -83,7 +72,7 @@ func (u *js) newTable(name, config, defaultvalue string) (id int64, err error) {
if err != nil {
return 0, err
}
globalTableHandle.Store(id, t)
u.globalTableHandle.Store(id, t)
return id, nil
}
......@@ -106,42 +95,43 @@ func (u *js) newTableFunc(vm *otto.Otto, name string) {
}
//CloseTable 关闭表格释放内存
func closeTable(id int64) error {
_, ok := globalTableHandle.Load(id)
func (u *js) closeTable(id int64) error {
_, ok := u.globalTableHandle.Load(id)
if !ok {
return types.ErrNotFound
}
globalTableHandle.Delete(id)
u.globalTableHandle.Delete(id)
return nil
}
func getTable(id int64) (*table.Table, error) {
if value, ok := globalTableHandle.Load(id); ok {
func (u *js) getTable(id int64) (*table.Table, error) {
if value, ok := u.globalTableHandle.Load(id); ok {
return value.(*table.Table), nil
}
return nil, types.ErrNotFound
}
func getTabler(id int64) (tabler, error) {
if value, ok := globalTableHandle.Load(id); ok {
func (u *js) getTabler(id int64) (tabler, error) {
if value, ok := u.globalTableHandle.Load(id); ok {
return value.(tabler), nil
}
return nil, types.ErrNotFound
}
func registerTableFunc(vm *otto.Otto) {
tableAddFunc(vm)
tableReplaceFunc(vm)
tableDelFunc(vm)
tableCloseFunc(vm)
tableSave(vm)
tableJoinFunc(vm)
tableQueryFunc(vm)
tableGetFunc(vm)
tableJoinKeyFunc(vm)
func (u *js) registerTableFunc(vm *otto.Otto, name string) {
u.newTableFunc(vm, name)
u.tableAddFunc(vm)
u.tableReplaceFunc(vm)
u.tableDelFunc(vm)
u.tableCloseFunc(vm)
u.tableSave(vm)
u.tableJoinFunc(vm)
u.tableQueryFunc(vm)
u.tableGetFunc(vm)
u.tableJoinKeyFunc(vm)
}
func tableJoinKeyFunc(vm *otto.Otto) {
func (u *js) tableJoinKeyFunc(vm *otto.Otto) {
vm.Set("table_joinkey", func(call otto.FunctionCall) otto.Value {
left, err := call.Argument(0).ToString()
if err != nil {
......@@ -156,13 +146,13 @@ func tableJoinKeyFunc(vm *otto.Otto) {
})
}
func tableAddFunc(vm *otto.Otto) {
func (u *js) tableAddFunc(vm *otto.Otto) {
vm.Set("table_add", func(call otto.FunctionCall) otto.Value {
id, err := call.Argument(0).ToInteger()
if err != nil {
return errReturn(vm, err)
}
tab, err := getTable(id)
tab, err := u.getTable(id)
if err != nil {
return errReturn(vm, err)
}
......@@ -178,13 +168,13 @@ func tableAddFunc(vm *otto.Otto) {
})
}
func tableReplaceFunc(vm *otto.Otto) {
func (u *js) tableReplaceFunc(vm *otto.Otto) {
vm.Set("table_replace", func(call otto.FunctionCall) otto.Value {
id, err := call.Argument(0).ToInteger()
if err != nil {
return errReturn(vm, err)
}
tab, err := getTable(id)
tab, err := u.getTable(id)
if err != nil {
return errReturn(vm, err)
}
......@@ -200,13 +190,13 @@ func tableReplaceFunc(vm *otto.Otto) {
})
}
func tableDelFunc(vm *otto.Otto) {
func (u *js) tableDelFunc(vm *otto.Otto) {
vm.Set("table_del", func(call otto.FunctionCall) otto.Value {
id, err := call.Argument(0).ToInteger()
if err != nil {
return errReturn(vm, err)
}
tab, err := getTable(id)
tab, err := u.getTable(id)
if err != nil {
return errReturn(vm, err)
}
......@@ -222,13 +212,13 @@ func tableDelFunc(vm *otto.Otto) {
})
}
func tableGetFunc(vm *otto.Otto) {
func (u *js) tableGetFunc(vm *otto.Otto) {
vm.Set("table_get", func(call otto.FunctionCall) otto.Value {
id, err := call.Argument(0).ToInteger()
if err != nil {
return errReturn(vm, err)
}
tab, err := getTabler(id)
tab, err := u.getTable(id)
if err != nil {
return errReturn(vm, err)
}
......@@ -256,13 +246,13 @@ type tabler interface {
Save() (kvs []*types.KeyValue, err error)
}
func tableSave(vm *otto.Otto) {
func (u *js) tableSave(vm *otto.Otto) {
vm.Set("table_save", func(call otto.FunctionCall) otto.Value {
id, err := call.Argument(0).ToInteger()
if err != nil {
return errReturn(vm, err)
}
tab, err := getTabler(id)
tab, err := u.getTabler(id)
if err != nil {
return errReturn(vm, err)
}
......@@ -274,13 +264,13 @@ func tableSave(vm *otto.Otto) {
})
}
func tableCloseFunc(vm *otto.Otto) {
func (u *js) tableCloseFunc(vm *otto.Otto) {
vm.Set("table_close", func(call otto.FunctionCall) otto.Value {
id, err := call.Argument(0).ToInteger()
if err != nil {
return errReturn(vm, err)
}
err = closeTable(id)
err = u.closeTable(id)
if err != nil {
return errReturn(vm, err)
}
......@@ -288,13 +278,13 @@ func tableCloseFunc(vm *otto.Otto) {
})
}
func tableQueryFunc(vm *otto.Otto) {
func (u *js) tableQueryFunc(vm *otto.Otto) {
vm.Set("table_query", func(call otto.FunctionCall) otto.Value {
id, err := call.Argument(0).ToInteger()
if err != nil {
return errReturn(vm, err)
}
tab, err := getTabler(id)
tab, err := u.getTabler(id)
if err != nil {
return errReturn(vm, err)
}
......@@ -333,7 +323,7 @@ func tableQueryFunc(vm *otto.Otto) {
return errReturn(vm, err)
}
_, isjoin := tab.(*table.JoinTable)
querylist := make([]*otto.Object, len(rows))
querylist := make([]interface{}, len(rows))
for i := 0; i < len(rows); i++ {
if isjoin {
joindata, ok := rows[i].Data.(*table.JoinData)
......@@ -348,16 +338,18 @@ func tableQueryFunc(vm *otto.Otto) {
if !ok {
return errReturn(vm, errors.New("rightdata is not jslog"))
}
obj := newObject(vm).setValue("left", leftdata.Data)
obj.setValue("right", rightdata.Data)
querylist[i] = obj.object()
obj := make(map[string]interface{})
obj["left"] = leftdata.Data
obj["right"] = rightdata.Data
querylist[i] = obj
} else {
leftdata, ok := rows[i].Data.(*jsproto.JsLog)
if !ok {
return errReturn(vm, errors.New("data is not JsLog"))
}
obj := newObject(vm).setValue("left", leftdata.Data)
querylist[i] = obj.object()
obj := make(map[string]interface{})
obj["left"] = leftdata.Data
querylist[i] = obj
}
}
retvalue, err := vm.ToValue(querylist)
......@@ -368,13 +360,13 @@ func tableQueryFunc(vm *otto.Otto) {
})
}
func tableJoinFunc(vm *otto.Otto) {
func (u *js) tableJoinFunc(vm *otto.Otto) {
vm.Set("new_join_table", func(call otto.FunctionCall) otto.Value {
left, err := call.Argument(0).ToInteger()
if err != nil {
return errReturn(vm, err)
}
lefttab, err := getTable(left)
lefttab, err := u.getTable(left)
if err != nil {
return errReturn(vm, err)
}
......@@ -382,7 +374,7 @@ func tableJoinFunc(vm *otto.Otto) {
if err != nil {
return errReturn(vm, err)
}
righttab, err := getTable(right)
righttab, err := u.getTable(right)
if err != nil {
return errReturn(vm, err)
}
......@@ -395,18 +387,9 @@ func tableJoinFunc(vm *otto.Otto) {
return errReturn(vm, err)
}
var id int64
for {
id = atomic.AddInt64(&globalHanldeID, 1) % maxjsint
if _, ok := globalTableHandle.Load(id); ok {
continue
}
if id < 0 {
atomic.StoreInt64(&globalHanldeID, 0)
continue
}
break
}
globalTableHandle.Store(id, join)
u.globalHanldeID++
id = u.globalHanldeID
u.globalTableHandle.Store(id, join)
return newObject(vm).setValue("id", id).value()
})
}
......@@ -428,18 +411,25 @@ handle := new_join_table(left, right, listofjoinindex)
//JSONRow meta
type JSONRow struct {
*jsproto.JsLog
config map[string]string
data map[string]interface{}
config map[string]string
data map[string]interface{}
lastdata types.Message
isint *regexp.Regexp
isfloat *regexp.Regexp
defaultvalue string
}
//NewJSONRow 创建一个row
func NewJSONRow(config string, defaultvalue string) (*JSONRow, error) {
row := &JSONRow{}
row.isint = regexp.MustCompile(`%\d*d`)
row.isfloat = regexp.MustCompile(`%[\.\d]*f`)
row.config = make(map[string]string)
err := json.Unmarshal([]byte(config), row.config)
err := json.Unmarshal([]byte(config), &row.config)
if err != nil {
return nil, err
}
row.defaultvalue = defaultvalue
row.JsLog = &jsproto.JsLog{Data: defaultvalue}
err = row.parse()
if err != nil {
......@@ -450,16 +440,25 @@ func NewJSONRow(config string, defaultvalue string) (*JSONRow, error) {
//CreateRow 创建一行
func (row *JSONRow) CreateRow() *table.Row {
return &table.Row{Data: &jsproto.JsLog{}}
return &table.Row{Data: &jsproto.JsLog{Data: row.defaultvalue}}
}
func (row *JSONRow) parse() error {
row.data = make(map[string]interface{})
return json.Unmarshal([]byte(row.JsLog.Data), row.data)
d := json.NewDecoder(bytes.NewBufferString(row.JsLog.Data))
d.UseNumber()
if err := d.Decode(&row.data); err != nil {
return err
}
return nil
}
//SetPayload 设置行的内容
func (row *JSONRow) SetPayload(data types.Message) error {
if row.lastdata == data {
return nil
}
row.lastdata = data
if rowdata, ok := data.(*jsproto.JsLog); ok {
row.JsLog = rowdata
return row.parse()
......@@ -471,6 +470,24 @@ func (row *JSONRow) SetPayload(data types.Message) error {
func (row *JSONRow) Get(key string) ([]byte, error) {
if format, ok := row.config[key]; ok {
if data, ok := row.data[key]; ok {
if n, ok := data.(json.Number); ok {
if row.isint.Match([]byte(format)) { //ini
num, err := n.Int64()
if err != nil {
return nil, err
}
return []byte(fmt.Sprintf(format, num)), nil
} else if row.isfloat.Match([]byte(format)) {
num, err := n.Float64()
if err != nil {
return nil, err
}
return []byte(fmt.Sprintf(format, num)), nil
} else {
s := n.String()
return []byte(fmt.Sprintf(format, s)), nil
}
}
return []byte(fmt.Sprintf(format, data)), nil
}
}
......
......@@ -205,6 +205,27 @@ func (mock *Chain33Mock) SendAndSign(priv crypto.PrivKey, hextx string) ([]byte,
return reply.GetMsg(), nil
}
//SendAndSignNonce 用外部传入的nonce 重写nonce
func (mock *Chain33Mock) SendAndSignNonce(priv crypto.PrivKey, hextx string, nonce int64) ([]byte, error) {
txbytes, err := hex.DecodeString(hextx)
if err != nil {
return nil, err
}
tx := &types.Transaction{}
err = types.Decode(txbytes, tx)
if err != nil {
return nil, err
}
tx.Nonce = nonce
tx.Fee = 1e6
tx.Sign(types.SECP256K1, priv)
reply, err := mock.api.SendTx(tx)
if err != nil {
return nil, err
}
return reply.GetMsg(), nil
}
func newWalletRealize(qAPI client.QueueProtocolAPI) {
seed := &types.SaveSeedByPw{
Seed: "subject hamster apple parent vital can adult chapter fork business humor pen tiger void elephant",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment