Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
plugin
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
link33
plugin
Commits
7b849e3c
Commit
7b849e3c
authored
Jan 07, 2019
by
张振华
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into guess
parents
03065e62
69aba101
Hide whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
2342 additions
and
334 deletions
+2342
-334
js.go
plugin/dapp/js/cmd/js.go
+160
-0
doc.go
plugin/dapp/js/doc.go
+53
-0
1.html
plugin/dapp/js/executor/1.html
+7
-2
account.go
plugin/dapp/js/executor/account.go
+3
-3
const.go
plugin/dapp/js/executor/const.go
+498
-42
const_test.go
plugin/dapp/js/executor/const_test.go
+279
-0
game.js
plugin/dapp/js/executor/game.js
+242
-0
gen.sh
plugin/dapp/js/executor/gen.sh
+15
-0
js.go
plugin/dapp/js/executor/js.go
+24
-19
jsvm.go
plugin/dapp/js/executor/jsvm.go
+1
-0
jsvm_test.go
plugin/dapp/js/executor/jsvm_test.go
+7
-7
query.go
plugin/dapp/js/executor/query.go
+3
-0
rpc_test.go
plugin/dapp/js/executor/rpc_test.go
+205
-44
runtime.go
plugin/dapp/js/executor/runtime.go
+12
-0
runtime.js
plugin/dapp/js/executor/runtime.js
+229
-28
table.go
plugin/dapp/js/executor/table.go
+214
-64
test.js
plugin/dapp/js/executor/test.js
+0
-18
plugin.go
plugin/dapp/js/plugin.go
+3
-2
while.sh
vendor/github.com/33cn/chain33/build/while.sh
+2
-0
chain33.test.toml
vendor/github.com/33cn/chain33/cmd/chain33/chain33.test.toml
+7
-2
table.go
vendor/github.com/33cn/chain33/common/db/table/table.go
+23
-1
base.go
vendor/github.com/33cn/chain33/system/store/base.go
+67
-49
tree.go
vendor/github.com/33cn/chain33/system/store/mavl/db/tree.go
+4
-12
mavl.go
vendor/github.com/33cn/chain33/system/store/mavl/mavl.go
+25
-26
cfg.go
vendor/github.com/33cn/chain33/types/cfg.go
+23
-15
chain33.go
vendor/github.com/33cn/chain33/util/cli/chain33.go
+5
-0
healthcheck.go
vendor/github.com/33cn/chain33/util/healthcheck.go
+156
-0
healthcheck_test.go
vendor/github.com/33cn/chain33/util/healthcheck_test.go
+54
-0
testnode.go
vendor/github.com/33cn/chain33/util/testnode/testnode.go
+21
-0
No files found.
plugin/dapp/js/cmd/js.go
0 → 100644
View file @
7b849e3c
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package
cmd
import
(
"fmt"
"io/ioutil"
"os"
"github.com/33cn/chain33/rpc/jsonclient"
rpctypes
"github.com/33cn/chain33/rpc/types"
"github.com/33cn/chain33/types"
jsty
"github.com/33cn/plugin/plugin/dapp/js/types"
"github.com/33cn/plugin/plugin/dapp/js/types/jsproto"
//"github.com/gojson"
"github.com/spf13/cobra"
)
//JavaScriptCmd :
func
JavaScriptCmd
()
*
cobra
.
Command
{
cmd
:=
&
cobra
.
Command
{
Use
:
"jsvm"
,
Short
:
"Java Script VM contract"
,
Args
:
cobra
.
MinimumNArgs
(
1
),
}
cmd
.
AddCommand
(
JavaScriptCreateCmd
(),
JavaScriptCallCmd
(),
JavaScriptQueryCmd
(),
)
return
cmd
}
// JavaScriptCreateCmd :
func
JavaScriptCreateCmd
()
*
cobra
.
Command
{
cmd
:=
&
cobra
.
Command
{
Use
:
"create"
,
Short
:
"create java script contract"
,
Run
:
createJavaScriptContract
,
}
createJavaScriptContractFlags
(
cmd
)
return
cmd
}
func
createJavaScriptContractFlags
(
cmd
*
cobra
.
Command
)
{
cmd
.
Flags
()
.
StringP
(
"code"
,
"c"
,
""
,
"path of js file,it must always be in utf-8."
)
cmd
.
MarkFlagRequired
(
"code"
)
cmd
.
Flags
()
.
StringP
(
"name"
,
"n"
,
""
,
"contract name"
)
cmd
.
MarkFlagRequired
(
"name"
)
}
func
createJavaScriptContract
(
cmd
*
cobra
.
Command
,
args
[]
string
)
{
rpcLaddr
,
_
:=
cmd
.
Flags
()
.
GetString
(
"rpc_laddr"
)
patch
,
_
:=
cmd
.
Flags
()
.
GetString
(
"code"
)
name
,
_
:=
cmd
.
Flags
()
.
GetString
(
"name"
)
codestr
,
err
:=
ioutil
.
ReadFile
(
patch
)
if
err
!=
nil
{
fmt
.
Fprintln
(
os
.
Stderr
,
err
)
return
}
create
:=
&
jsproto
.
Create
{
Code
:
string
(
codestr
),
Name
:
name
,
}
params
:=
&
rpctypes
.
CreateTxIn
{
Execer
:
jsty
.
JsX
,
ActionName
:
"Create"
,
Payload
:
types
.
MustPBToJSON
(
create
),
}
var
res
string
ctx
:=
jsonclient
.
NewRPCCtx
(
rpcLaddr
,
"Chain33.CreateTransaction"
,
params
,
&
res
)
ctx
.
RunWithoutMarshal
()
}
// JavaScriptCallCmd :
func
JavaScriptCallCmd
()
*
cobra
.
Command
{
cmd
:=
&
cobra
.
Command
{
Use
:
"call"
,
Short
:
"call java script contract"
,
Run
:
callJavaScript
,
}
callJavaScriptFlags
(
cmd
)
return
cmd
}
func
callJavaScriptFlags
(
cmd
*
cobra
.
Command
)
{
cmd
.
Flags
()
.
StringP
(
"name"
,
"n"
,
""
,
"java script contract name"
)
cmd
.
MarkFlagRequired
(
"name"
)
cmd
.
Flags
()
.
StringP
(
"funcname"
,
"f"
,
""
,
"java script contract funcname"
)
cmd
.
MarkFlagRequired
(
"funcname"
)
cmd
.
Flags
()
.
StringP
(
"args"
,
"a"
,
""
,
"json str of args"
)
}
func
callJavaScript
(
cmd
*
cobra
.
Command
,
args
[]
string
)
{
rpcLaddr
,
_
:=
cmd
.
Flags
()
.
GetString
(
"rpc_laddr"
)
name
,
_
:=
cmd
.
Flags
()
.
GetString
(
"name"
)
funcname
,
_
:=
cmd
.
Flags
()
.
GetString
(
"funcname"
)
input
,
_
:=
cmd
.
Flags
()
.
GetString
(
"args"
)
call
:=
&
jsproto
.
Call
{
Name
:
name
,
Funcname
:
funcname
,
Args
:
input
,
}
params
:=
&
rpctypes
.
CreateTxIn
{
Execer
:
"user."
+
jsty
.
JsX
+
"."
+
name
,
ActionName
:
"Call"
,
Payload
:
types
.
MustPBToJSON
(
call
),
}
var
res
string
ctx
:=
jsonclient
.
NewRPCCtx
(
rpcLaddr
,
"Chain33.CreateTransaction"
,
params
,
&
res
)
ctx
.
RunWithoutMarshal
()
}
//JavaScriptQueryCmd :
func
JavaScriptQueryCmd
()
*
cobra
.
Command
{
cmd
:=
&
cobra
.
Command
{
Use
:
"query"
,
Short
:
"query java script contract"
,
Run
:
queryJavaScript
,
}
queryJavaScriptFlags
(
cmd
)
return
cmd
}
func
queryJavaScriptFlags
(
cmd
*
cobra
.
Command
)
{
cmd
.
Flags
()
.
StringP
(
"name"
,
"n"
,
""
,
"java script contract name"
)
cmd
.
MarkFlagRequired
(
"name"
)
cmd
.
Flags
()
.
StringP
(
"funcname"
,
"f"
,
""
,
"java script contract funcname"
)
cmd
.
MarkFlagRequired
(
"funcname"
)
cmd
.
Flags
()
.
StringP
(
"args"
,
"a"
,
""
,
"json str of args"
)
}
func
queryJavaScript
(
cmd
*
cobra
.
Command
,
args
[]
string
)
{
rpcLaddr
,
_
:=
cmd
.
Flags
()
.
GetString
(
"rpc_laddr"
)
name
,
_
:=
cmd
.
Flags
()
.
GetString
(
"name"
)
funcname
,
_
:=
cmd
.
Flags
()
.
GetString
(
"funcname"
)
input
,
_
:=
cmd
.
Flags
()
.
GetString
(
"args"
)
var
params
rpctypes
.
Query4Jrpc
var
rep
interface
{}
req
:=
&
jsproto
.
Call
{
Name
:
name
,
Funcname
:
funcname
,
Args
:
input
,
}
params
.
Execer
=
jsty
.
JsX
params
.
FuncName
=
"Query"
params
.
Payload
=
types
.
MustPBToJSON
(
req
)
rep
=
&
jsproto
.
QueryResult
{}
ctx
:=
jsonclient
.
NewRPCCtx
(
rpcLaddr
,
"Chain33.Query"
,
params
,
rep
)
ctx
.
Run
()
}
plugin/dapp/js/doc.go
0 → 100644
View file @
7b849e3c
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package
js
/*
Java Script VM contract
cli 命令行
Available Commands:
call call java script contract
create create java script contract
query query java script contract
cli jsvm create
Flags:
-c, --code string path of js file,it must always be in utf-8.
-h, --help help for create
-n, --name string contract name
cli jsvm call
Flags:
-a, --args string json str of args
-f, --funcname string java script contract funcname
-h, --help help for call
-n, --name string java script contract name
cli jsvm query
Flags:
-a, --args string json str of args
-f, --funcname string java script contract funcname
-h, --help help for query
-n, --name string java script contract name
测试步骤:
第一步:创建钱包
cli seed save -p heyubin -s "voice leisure mechanic tape cluster grunt receive joke nurse between monkey lunch save useful cruise"
cli wallet unlock -p heyubin
cli account import_key -l miner -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944
第二步:创建名为test的js合约,合约代码使用test.js代码文件(必须是utf-8格式)
cli send jsvm create -c "../plugin/dapp/js/executor/test.js" -n test -k 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt
第三步:调用test合约的hello函数
cli send jsvm call -a "{\"hello\": \"world\"}" -f hello -n test -k 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt
第四步:query test合约hello函数
cli jsvm query -a "{\"hello\": \"world\"}" -f hello -n test
*/
plugin/dapp/js/executor/1.html
View file @
7b849e3c
<script
src=
"runtime.js"
></script>
<script
src=
"runtime.js"
></script>
<script
src=
"
test
.js"
></script>
<script
src=
"
game
.js"
></script>
<script>
<script>
//demo database function
//demo database function
var
statedb
=
{}
var
statedb
=
{}
...
@@ -34,11 +34,15 @@ function getstatedb(key) {
...
@@ -34,11 +34,15 @@ function getstatedb(key) {
return
statedb
[
key
]
return
statedb
[
key
]
}
}
function
execname
()
{
return
"user.jsvm.test"
}
function
setstatedb
(
kvs
)
{
function
setstatedb
(
kvs
)
{
for
(
var
i
=
0
;
i
<
kvs
.
length
;
i
++
)
{
for
(
var
i
=
0
;
i
<
kvs
.
length
;
i
++
)
{
statedb
[
kvs
[
i
].
key
]
=
kvs
[
i
].
value
statedb
[
kvs
[
i
].
key
]
=
kvs
[
i
].
value
}
}
}
}
var
ret
=
callcode
(
"{}"
,
"exec
local_hello
"
,
"{}"
,
[])
var
ret
=
callcode
(
"{}"
,
"exec
_NewGame
"
,
"{}"
,
[])
console
.
log
(
ret
)
console
.
log
(
ret
)
</script>
</script>
\ No newline at end of file
plugin/dapp/js/executor/account.go
View file @
7b849e3c
...
@@ -282,7 +282,7 @@ func (u *js) execFrozenFunc(vm *otto.Otto) {
...
@@ -282,7 +282,7 @@ func (u *js) execFrozenFunc(vm *otto.Otto) {
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
receipt
,
err
:=
acc
.
ExecFrozen
(
addr
ess
.
ExecAddress
(
execer
),
addr
,
amount
)
receipt
,
err
:=
acc
.
ExecFrozen
(
addr
,
address
.
ExecAddress
(
execer
)
,
amount
)
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
...
@@ -311,7 +311,7 @@ func (u *js) execActiveFunc(vm *otto.Otto) {
...
@@ -311,7 +311,7 @@ func (u *js) execActiveFunc(vm *otto.Otto) {
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
receipt
,
err
:=
acc
.
ExecActive
(
addr
ess
.
ExecAddress
(
execer
),
addr
,
amount
)
receipt
,
err
:=
acc
.
ExecActive
(
addr
,
address
.
ExecAddress
(
execer
)
,
amount
)
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
...
@@ -340,7 +340,7 @@ func (u *js) execDepositFunc(vm *otto.Otto) {
...
@@ -340,7 +340,7 @@ func (u *js) execDepositFunc(vm *otto.Otto) {
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
receipt
,
err
:=
acc
.
ExecDeposit
(
addr
ess
.
ExecAddress
(
execer
),
addr
,
amount
)
receipt
,
err
:=
acc
.
ExecDeposit
(
addr
,
address
.
ExecAddress
(
execer
)
,
amount
)
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
...
...
plugin/dapp/js/executor/const.go
View file @
7b849e3c
...
@@ -3,14 +3,15 @@ package executor
...
@@ -3,14 +3,15 @@ package executor
var
callcode
=
`
var
callcode
=
`
var tojson = JSON.stringify
var tojson = JSON.stringify
//table warp
//table warp
function
t
able(kvc, config, defaultvalue) {
function
T
able(kvc, config, defaultvalue) {
var ret = table_new(
config, defaultvalue
)
var ret = table_new(
tojson(config), tojson(defaultvalue)
)
if (ret.err) {
if (ret.err) {
throw new Error(ret.err)
throw new Error(ret.err)
}
}
this.kvc = kvc
this.kvc = kvc
this.id = ret.id
this.id = ret.id
this.config = config
this.config = config
this.name = config["#tablename"]
this.defaultvalue = defaultvalue
this.defaultvalue = defaultvalue
}
}
...
@@ -18,7 +19,7 @@ function isstring(obj) {
...
@@ -18,7 +19,7 @@ function isstring(obj) {
return typeof obj === "string"
return typeof obj === "string"
}
}
t
able.prototype.add = function(obj) {
T
able.prototype.add = function(obj) {
if (!isstring(obj)) {
if (!isstring(obj)) {
obj = tojson(obj)
obj = tojson(obj)
}
}
...
@@ -26,7 +27,57 @@ table.prototype.add = function(obj) {
...
@@ -26,7 +27,57 @@ table.prototype.add = function(obj) {
return ret.err
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) {
if (!isstring(row)) {
row = tojson(row)
}
var ret = table_get(this.id, key, row)
if (ret.err) {
throwerr(ret.err)
}
return ret.value
}
function query_list(indexName, prefix, primaryKey, count, direction) {
if (count !== 0 && !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)
if (q.err) {
return null
}
for (var i = 0; i < q.length; i++) {
if (q[i].left) {
q[i].left = JSON.parse(q[i].left)
}
if (q[i].right) {
q[i].right = JSON.parse(q[i].right)
}
}
return q
}
Table.prototype.query = function(indexName, prefix, primaryKey, count, direction) {
return query_list.call(this, indexName, prefix, primaryKey, count, direction)
}
Table.prototype.replace = function(obj) {
if (!isstring(obj)) {
if (!isstring(obj)) {
obj = tojson(obj)
obj = tojson(obj)
}
}
...
@@ -34,7 +85,7 @@ table.prototype.replace = function(obj) {
...
@@ -34,7 +85,7 @@ table.prototype.replace = function(obj) {
return ret.err
return ret.err
}
}
t
able.prototype.del = function(obj) {
T
able.prototype.del = function(obj) {
if (!isstring(obj)) {
if (!isstring(obj)) {
obj = tojson(obj)
obj = tojson(obj)
}
}
...
@@ -42,7 +93,7 @@ table.prototype.del = function(obj) {
...
@@ -42,7 +93,7 @@ table.prototype.del = function(obj) {
return ret.err
return ret.err
}
}
t
able.prototype.save = function() {
T
able.prototype.save = function() {
var ret = table_save(this.id)
var ret = table_save(this.id)
if (!this.kvc) {
if (!this.kvc) {
this.kvc.save(ret)
this.kvc.save(ret)
...
@@ -50,11 +101,89 @@ table.prototype.save = function() {
...
@@ -50,11 +101,89 @@ table.prototype.save = function() {
return ret
return ret
}
}
t
able.prototype.close = function() {
T
able.prototype.close = function() {
var ret = table_close(this.id)
var ret = table_close(this.id)
return ret.err
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.get = function(key, row) {
if (!isstring(row)) {
row = tojson(row)
}
var ret = table_get(this.id, key, row)
if (ret.err) {
throwerr(ret.err)
}
return ret.value
}
JoinTable.prototype.query = function(indexName, prefix, primaryKey, count, direction) {
return query_list.call(this, indexName, prefix, primaryKey, count, direction)
}
function querytojson(data) {
if (!data) {
return "[]"
}
return tojson(data)
}
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
//account warp
function account(kvc, execer, symbol) {
function account(kvc, execer, symbol) {
this.execer = execer
this.execer = execer
...
@@ -64,7 +193,7 @@ function account(kvc, execer, symbol) {
...
@@ -64,7 +193,7 @@ function account(kvc, execer, symbol) {
account.prototype.genesisInit = function(addr, amount) {
account.prototype.genesisInit = function(addr, amount) {
var ret = genesis_init(this, addr, amount)
var ret = genesis_init(this, addr, amount)
if (
!
this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
this.kvc.save(ret)
}
}
return ret.err
return ret.err
...
@@ -72,7 +201,7 @@ account.prototype.genesisInit = function(addr, amount) {
...
@@ -72,7 +201,7 @@ account.prototype.genesisInit = function(addr, amount) {
account.prototype.execGenesisInit = function(execer, addr, amount) {
account.prototype.execGenesisInit = function(execer, addr, amount) {
var ret = genesis_init_exec(this, execer, addr, amount)
var ret = genesis_init_exec(this, execer, addr, amount)
if (
!
this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
this.kvc.save(ret)
}
}
return ret.err
return ret.err
...
@@ -89,7 +218,7 @@ account.prototype.execGetBalance = function(execer, addr) {
...
@@ -89,7 +218,7 @@ account.prototype.execGetBalance = function(execer, addr) {
//本合约转移资产,或者转移到其他合约,或者从其他合约取回资产
//本合约转移资产,或者转移到其他合约,或者从其他合约取回资产
account.prototype.transfer = function(from, to, amount) {
account.prototype.transfer = function(from, to, amount) {
var ret = transfer(this, from, to, amount)
var ret = transfer(this, from, to, amount)
if (
!
this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
this.kvc.save(ret)
}
}
return ret.err
return ret.err
...
@@ -97,7 +226,7 @@ account.prototype.transfer = function(from, to, amount) {
...
@@ -97,7 +226,7 @@ account.prototype.transfer = function(from, to, amount) {
account.prototype.transferToExec = function(execer, from, amount) {
account.prototype.transferToExec = function(execer, from, amount) {
var ret = transfer_to_exec(this, execer, from, amount)
var ret = transfer_to_exec(this, execer, from, amount)
if (
!
this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
this.kvc.save(ret)
}
}
return ret.err
return ret.err
...
@@ -105,7 +234,7 @@ account.prototype.transferToExec = function(execer, from, amount) {
...
@@ -105,7 +234,7 @@ account.prototype.transferToExec = function(execer, from, amount) {
account.prototype.withdrawFromExec = function(execer, to, amount) {
account.prototype.withdrawFromExec = function(execer, to, amount) {
var ret = withdraw(this, execer, to, amount)
var ret = withdraw(this, execer, to, amount)
if (
!
this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
this.kvc.save(ret)
}
}
return ret.err
return ret.err
...
@@ -114,7 +243,7 @@ account.prototype.withdrawFromExec = function(execer, to, amount) {
...
@@ -114,7 +243,7 @@ account.prototype.withdrawFromExec = function(execer, to, amount) {
//管理其他合约的资产转移到这个合约中
//管理其他合约的资产转移到这个合约中
account.prototype.execActive = function(execer, addr, amount) {
account.prototype.execActive = function(execer, addr, amount) {
var ret = exec_active(this, execer, addr, amount)
var ret = exec_active(this, execer, addr, amount)
if (
!
this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
this.kvc.save(ret)
}
}
return ret.err
return ret.err
...
@@ -122,7 +251,7 @@ account.prototype.execActive = function(execer, addr, amount) {
...
@@ -122,7 +251,7 @@ account.prototype.execActive = function(execer, addr, amount) {
account.prototype.execFrozen = function(execer, addr, amount) {
account.prototype.execFrozen = function(execer, addr, amount) {
var ret = exec_frozen(this, execer, addr, amount)
var ret = exec_frozen(this, execer, addr, amount)
if (
!
this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
this.kvc.save(ret)
}
}
return ret.err
return ret.err
...
@@ -130,7 +259,7 @@ account.prototype.execFrozen = function(execer, addr, amount) {
...
@@ -130,7 +259,7 @@ account.prototype.execFrozen = function(execer, addr, amount) {
account.prototype.execDeposit = function(execer, addr, amount) {
account.prototype.execDeposit = function(execer, addr, amount) {
var ret = exec_deposit(this, execer, addr, amount)
var ret = exec_deposit(this, execer, addr, amount)
if (
!
this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
this.kvc.save(ret)
}
}
return ret.err
return ret.err
...
@@ -138,7 +267,7 @@ account.prototype.execDeposit = function(execer, addr, amount) {
...
@@ -138,7 +267,7 @@ account.prototype.execDeposit = function(execer, addr, amount) {
account.prototype.execWithdraw = function(execer, addr, amount) {
account.prototype.execWithdraw = function(execer, addr, amount) {
var ret = exec_withdraw(this, execer, addr, amount)
var ret = exec_withdraw(this, execer, addr, amount)
if (
!
this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
this.kvc.save(ret)
}
}
return ret.err
return ret.err
...
@@ -146,12 +275,47 @@ account.prototype.execWithdraw = function(execer, addr, amount) {
...
@@ -146,12 +275,47 @@ account.prototype.execWithdraw = function(execer, addr, amount) {
account.prototype.execTransfer = function(execer, from, to, amount) {
account.prototype.execTransfer = function(execer, from, to, amount) {
var ret = exec_transfer(this, execer, from, to, amount)
var ret = exec_transfer(this, execer, from, to, amount)
if (
!
this.kvc) {
if (this.kvc) {
this.kvc.save(ret)
this.kvc.save(ret)
}
}
return ret.err
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
}
err = 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) {
function kvcreator(dbtype) {
this.data = {}
this.data = {}
this.kvs = []
this.kvs = []
...
@@ -161,11 +325,11 @@ function kvcreator(dbtype) {
...
@@ -161,11 +325,11 @@ function kvcreator(dbtype) {
this.getloal = getlocaldb
this.getloal = getlocaldb
this.list = listdb
this.list = listdb
if (dbtype == "exec" || dbtype == "init") {
if (dbtype == "exec" || dbtype == "init") {
this.get
= this.getstatedb
this.get
db = this.getstate
} else if (dbtype == "local") {
} else if (dbtype == "local") {
this.get
= this.getlocaldb
this.get
db = this.getlocal
} else if (dbtype == "query") {
} else if (dbtype == "query") {
this.get
= this.getlocaldb
this.get
db = this.getlocal
} else {
} else {
throw new Error("chain33.js: dbtype error")
throw new Error("chain33.js: dbtype error")
}
}
...
@@ -184,8 +348,8 @@ kvcreator.prototype.get = function(k, prefix) {
...
@@ -184,8 +348,8 @@ kvcreator.prototype.get = function(k, prefix) {
if (this.data[k]) {
if (this.data[k]) {
v = this.data[k]
v = this.data[k]
} else {
} else {
var dbvalue = this.get
(k, !!prefix)
var dbvalue = this.getdb
(k, !!prefix)
if (dbvalue.err
!= ""
) {
if (dbvalue.err) {
return null
return null
}
}
v = dbvalue.value
v = dbvalue.value
...
@@ -213,7 +377,7 @@ kvcreator.prototype.save = function(receipt) {
...
@@ -213,7 +377,7 @@ kvcreator.prototype.save = function(receipt) {
kvcreator.prototype.listvalue = function(prefix, key, count, direction) {
kvcreator.prototype.listvalue = function(prefix, key, count, direction) {
var dbvalues = this.list(prefix, key, count, direction)
var dbvalues = this.list(prefix, key, count, direction)
if (dbvalues.err
!= ""
) {
if (dbvalues.err) {
return []
return []
}
}
var values = dbvalues.value
var values = dbvalues.value
...
@@ -247,6 +411,73 @@ kvcreator.prototype.receipt = function() {
...
@@ -247,6 +411,73 @@ kvcreator.prototype.receipt = function() {
return {kvs: this.kvs, logs: this.logs}
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)
}
}
Query.prototype.JoinKey = function(args) {
return table_joinkey(args.left, args.right).value
}
function throwerr(err, msg) {
if (err) {
throw new Error(err + ":" + msg)
}
}
function callcode(context, f, args, loglist) {
function callcode(context, f, args, loglist) {
if (f == "init") {
if (f == "init") {
return Init(JSON.parse(context))
return Init(JSON.parse(context))
...
@@ -276,7 +507,7 @@ function callcode(context, f, args, loglist) {
...
@@ -276,7 +507,7 @@ function callcode(context, f, args, loglist) {
}
}
var arg = JSON.parse(args)
var arg = JSON.parse(args)
if (typeof runobj[funcname] != "function") {
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)
return runobj[funcname](arg)
}
}
...
@@ -285,8 +516,6 @@ function callcode(context, f, args, loglist) {
...
@@ -285,8 +516,6 @@ function callcode(context, f, args, loglist) {
`
`
var
jscode
=
`
var
jscode
=
`
//数据结构设计
//数据结构设计
//kvlist [{key:"key1", value:"value1"},{key:"key2", value:"value2"}]
//log 设计 {json data}
function Init(context) {
function Init(context) {
this.kvc = new kvcreator("init")
this.kvc = new kvcreator("init")
this.context = context
this.context = context
...
@@ -295,22 +524,6 @@ function Init(context) {
...
@@ -295,22 +524,6 @@ function Init(context) {
return this.kvc.receipt()
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) {
Exec.prototype.hello = function(args) {
this.kvc.add("args", args)
this.kvc.add("args", args)
this.kvc.add("action", "exec")
this.kvc.add("action", "exec")
...
@@ -335,3 +548,246 @@ Query.prototype.hello = function(args) {
...
@@ -335,3 +548,246 @@ Query.prototype.hello = function(args) {
}
}
`
`
var
_
=
jscode
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
match.num = args.num
var game = this.kvc.get(match.gameid)
if (!game) {
throwerr("guess: game id not found")
}
if (game.status != 1) {
throwerr("guess: game status not open")
}
if (this.context.from == game.addr) {
throwerr("guess: game addr and match addr is same")
}
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, match.bet)
console.log(this.name, this.context.from, err)
throwerr(err)
this.kvc.add(match.id, match)
this.kvc.addlog(match)
return this.kvc.receipt()
}
Exec.prototype.CloseGame = function(args) {
var local = MatchLocalTable(this.kvc)
var game = this.kvc.get(args.gameid)
if (!game) {
throwerr("game id not found")
}
var querykey = local.get("gameid", args)
var matches = local.query("gameid", querykey, "", 0, 1)
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 "+MIN_WAIT_BLOCK+" block")
}
for (var i = 0; i < matches.length; i++) {
var match = matches[i].left
if (match.num == n) {
//不能随便添加辅助函数,因为可以被外界调用到,所以辅助函数都是传递 this
win.call(this, game, match)
} else {
fail.call(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(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)
throwerr(err, "execTransFrozenToActive")
game.bet -= amount
}
err = this.acc.execActive(this.name, match.addr, match.bet)
throwerr(err, "execActive")
}
function fail(game, match) {
var amount = match.bet
err = this.acc.execTransFrozenToFrozen(this.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.call(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) {
return localprocess.call(this, args)
}
ExecLocal.prototype.Guess = function(args) {
return localprocess.call(this, args)
}
ExecLocal.prototype.CloseGame = function(args) {
return localprocess.call(this, args)
}
ExecLocal.prototype.ForceCloseGame = function(args) {
return localprocess.call(this, args)
}
function localprocess(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)
var q = local.query("addr", args.addr, args.primaryKey, args.count, args.direction)
return querytojson(q)
}
Query.prototype.ListMatchByAddr = function(args) {
var local = MatchGameTable(this.kvc)
var q= local.query("addr#status", args["addr#status"], args.primaryKey, args.count, args.direction)
return querytojson(q)
}
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
plugin/dapp/js/executor/const_test.go
0 → 100644
View file @
7b849e3c
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
match.num = args.num
var game = this.kvc.get(match.gameid)
if (!game) {
throwerr("guess: game id not found")
}
if (game.status != 1) {
throwerr("guess: game status not open")
}
if (this.context.from == game.addr) {
throwerr("guess: game addr and match addr is same")
}
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, match.bet)
console.log(this.name, this.context.from, err)
throwerr(err)
this.kvc.add(match.id, match)
this.kvc.addlog(match)
return this.kvc.receipt()
}
Exec.prototype.CloseGame = function(args) {
var local = MatchLocalTable(this.kvc)
var game = this.kvc.get(args.gameid)
if (!game) {
throwerr("game id not found")
}
var querykey = local.get("gameid", args)
var matches = local.query("gameid", querykey, "", 0, 1)
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 "+MIN_WAIT_BLOCK+" block")
}
for (var i = 0; i < matches.length; i++) {
var match = matches[i].left
if (match.num == n) {
//不能随便添加辅助函数,因为可以被外界调用到,所以辅助函数都是传递 this
win.call(this, game, match)
} else {
fail.call(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(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)
throwerr(err, "execTransFrozenToActive")
game.bet -= amount
}
err = this.acc.execActive(this.name, match.addr, match.bet)
throwerr(err, "execActive")
}
function fail(game, match) {
var amount = match.bet
err = this.acc.execTransFrozenToFrozen(this.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.call(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) {
return localprocess.call(this, args)
}
ExecLocal.prototype.Guess = function(args) {
return localprocess.call(this, args)
}
ExecLocal.prototype.CloseGame = function(args) {
return localprocess.call(this, args)
}
ExecLocal.prototype.ForceCloseGame = function(args) {
return localprocess.call(this, args)
}
function localprocess(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)
var q = local.query("addr", args.addr, args.primaryKey, args.count, args.direction)
return querytojson(q)
}
Query.prototype.ListMatchByAddr = function(args) {
var local = MatchGameTable(this.kvc)
var q= local.query("addr#status", args["addr#status"], args.primaryKey, args.count, args.direction)
return querytojson(q)
}
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
plugin/dapp/js/executor/game.js
0 → 100644
View file @
7b849e3c
//简单的猜数字游戏
//游戏规则: 庄家出一个 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
match
.
num
=
args
.
num
var
game
=
this
.
kvc
.
get
(
match
.
gameid
)
if
(
!
game
)
{
throwerr
(
"guess: game id not found"
)
}
if
(
game
.
status
!=
1
)
{
throwerr
(
"guess: game status not open"
)
}
if
(
this
.
context
.
from
==
game
.
addr
)
{
throwerr
(
"guess: game addr and match addr is same"
)
}
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
,
match
.
bet
)
console
.
log
(
this
.
name
,
this
.
context
.
from
,
err
)
throwerr
(
err
)
this
.
kvc
.
add
(
match
.
id
,
match
)
this
.
kvc
.
addlog
(
match
)
return
this
.
kvc
.
receipt
()
}
Exec
.
prototype
.
CloseGame
=
function
(
args
)
{
var
local
=
MatchLocalTable
(
this
.
kvc
)
var
game
=
this
.
kvc
.
get
(
args
.
gameid
)
if
(
!
game
)
{
throwerr
(
"game id not found"
)
}
var
querykey
=
local
.
get
(
"gameid"
,
args
)
var
matches
=
local
.
query
(
"gameid"
,
querykey
,
""
,
0
,
1
)
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 "
+
MIN_WAIT_BLOCK
+
" block"
)
}
for
(
var
i
=
0
;
i
<
matches
.
length
;
i
++
)
{
var
match
=
matches
[
i
].
left
if
(
match
.
num
==
n
)
{
//不能随便添加辅助函数,因为可以被外界调用到,所以辅助函数都是传递 this
win
.
call
(
this
,
game
,
match
)
}
else
{
fail
.
call
(
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
(
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
)
throwerr
(
err
,
"execTransFrozenToActive"
)
game
.
bet
-=
amount
}
err
=
this
.
acc
.
execActive
(
this
.
name
,
match
.
addr
,
match
.
bet
)
throwerr
(
err
,
"execActive"
)
}
function
fail
(
game
,
match
)
{
var
amount
=
match
.
bet
err
=
this
.
acc
.
execTransFrozenToFrozen
(
this
.
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
.
call
(
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
)
{
return
localprocess
.
call
(
this
,
args
)
}
ExecLocal
.
prototype
.
Guess
=
function
(
args
)
{
return
localprocess
.
call
(
this
,
args
)
}
ExecLocal
.
prototype
.
CloseGame
=
function
(
args
)
{
return
localprocess
.
call
(
this
,
args
)
}
ExecLocal
.
prototype
.
ForceCloseGame
=
function
(
args
)
{
return
localprocess
.
call
(
this
,
args
)
}
function
localprocess
(
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
)
var
q
=
local
.
query
(
"addr"
,
args
.
addr
,
args
.
primaryKey
,
args
.
count
,
args
.
direction
)
return
querytojson
(
q
)
}
Query
.
prototype
.
ListMatchByAddr
=
function
(
args
)
{
var
local
=
MatchGameTable
(
this
.
kvc
)
var
q
=
local
.
query
(
"addr#status"
,
args
[
"addr#status"
],
args
.
primaryKey
,
args
.
count
,
args
.
direction
)
return
querytojson
(
q
)
}
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"
)
}
\ No newline at end of file
plugin/dapp/js/executor/gen.sh
View file @
7b849e3c
...
@@ -8,4 +8,19 @@
...
@@ -8,4 +8,19 @@
cat
"test.js"
cat
"test.js"
printf
'`\n'
printf
'`\n'
printf
'var _ = jscode\n'
printf
'var _ = jscode\n'
printf
'var gamecode = `\n'
cat
"game.js"
printf
'`\n'
printf
'var _ = gamecode\n'
}
>
const.go
}
>
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
plugin/dapp/js/executor/js.go
View file @
7b849e3c
...
@@ -3,7 +3,7 @@ package executor
...
@@ -3,7 +3,7 @@ package executor
import
(
import
(
"bytes"
"bytes"
"encoding/json"
"encoding/json"
"
fmt
"
"
sync
"
"sync/atomic"
"sync/atomic"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common"
...
@@ -28,7 +28,7 @@ func init() {
...
@@ -28,7 +28,7 @@ func init() {
panic
(
err
)
panic
(
err
)
}
}
execaddressFunc
(
basevm
)
execaddressFunc
(
basevm
)
registerTable
Func
(
basevm
)
sha256
Func
(
basevm
)
}
}
var
isinit
int64
var
isinit
int64
...
@@ -48,7 +48,9 @@ func Init(name string, sub []byte) {
...
@@ -48,7 +48,9 @@ func Init(name string, sub []byte) {
type
js
struct
{
type
js
struct
{
drivers
.
DriverBase
drivers
.
DriverBase
prefix
[]
byte
prefix
[]
byte
globalTableHandle
sync
.
Map
globalHanldeID
int64
}
}
func
newjs
()
drivers
.
Driver
{
func
newjs
()
drivers
.
Driver
{
...
@@ -173,6 +175,7 @@ func (u *js) getContext(tx *types.Transaction, index int64) *blockContext {
...
@@ -173,6 +175,7 @@ func (u *js) getContext(tx *types.Transaction, index int64) *blockContext {
Difficulty
:
u
.
GetDifficulty
(),
Difficulty
:
u
.
GetDifficulty
(),
TxHash
:
common
.
ToHex
(
hash
[
:
]),
TxHash
:
common
.
ToHex
(
hash
[
:
]),
Index
:
index
,
Index
:
index
,
From
:
tx
.
From
(),
}
}
}
}
...
@@ -222,7 +225,7 @@ func (u *js) localdbFunc(vm *otto.Otto, name string) {
...
@@ -222,7 +225,7 @@ func (u *js) localdbFunc(vm *otto.Otto, name string) {
func
(
u
*
js
)
execnameFunc
(
vm
*
otto
.
Otto
,
name
string
)
{
func
(
u
*
js
)
execnameFunc
(
vm
*
otto
.
Otto
,
name
string
)
{
vm
.
Set
(
"execname"
,
func
(
call
otto
.
FunctionCall
)
otto
.
Value
{
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
))
})
})
}
}
...
@@ -279,7 +282,7 @@ func (u *js) createVM(name string, tx *types.Transaction, index int) (*otto.Otto
...
@@ -279,7 +282,7 @@ func (u *js) createVM(name string, tx *types.Transaction, index int) (*otto.Otto
u
.
listdbFunc
(
vm
,
name
)
u
.
listdbFunc
(
vm
,
name
)
u
.
execnameFunc
(
vm
,
name
)
u
.
execnameFunc
(
vm
,
name
)
u
.
registerAccountFunc
(
vm
)
u
.
registerAccountFunc
(
vm
)
u
.
new
TableFunc
(
vm
,
name
)
u
.
register
TableFunc
(
vm
,
name
)
return
vm
,
nil
return
vm
,
nil
}
}
...
@@ -358,26 +361,28 @@ func (u *js) Allow(tx *types.Transaction, index int) error {
...
@@ -358,26 +361,28 @@ func (u *js) Allow(tx *types.Transaction, index int) error {
return
types
.
ErrNotAllow
return
types
.
ErrNotAllow
}
}
func
createKVObject
(
vm
*
otto
.
Otto
,
kvs
[]
*
types
.
KeyValue
)
otto
.
Value
{
func
createKVObject
(
vm
*
otto
.
Otto
,
kvs
[]
*
types
.
KeyValue
)
[]
interface
{}
{
obj
:=
newObjectString
(
vm
,
"([])"
)
data
:=
make
([]
interface
{},
len
(
kvs
)
)
for
i
:=
0
;
i
<
len
(
kvs
);
i
++
{
for
i
:=
0
;
i
<
len
(
kvs
);
i
++
{
item
:=
newObject
(
vm
)
.
setValue
(
"key"
,
string
(
kvs
[
i
]
.
Key
))
item
:=
make
(
map
[
string
]
interface
{})
item
.
setValue
(
"value"
,
string
(
kvs
[
i
]
.
Value
))
item
[
"key"
]
=
string
(
kvs
[
i
]
.
Key
)
item
.
setValue
(
"prefix"
,
true
)
item
[
"value"
]
=
string
(
kvs
[
i
]
.
Value
)
obj
.
setValue
(
fmt
.
Sprint
(
i
),
item
)
item
[
"prefix"
]
=
true
data
[
i
]
=
item
}
}
return
obj
.
value
()
return
data
}
}
func
createLogsObject
(
vm
*
otto
.
Otto
,
logs
[]
*
types
.
ReceiptLog
)
otto
.
Value
{
func
createLogsObject
(
vm
*
otto
.
Otto
,
logs
[]
*
types
.
ReceiptLog
)
[]
interface
{}
{
obj
:=
newObjectString
(
vm
,
"([])"
)
data
:=
make
([]
interface
{},
len
(
logs
)
)
for
i
:=
0
;
i
<
len
(
logs
);
i
++
{
for
i
:=
0
;
i
<
len
(
logs
);
i
++
{
item
:=
newObject
(
vm
)
.
setValue
(
"ty"
,
logs
[
i
]
.
Ty
)
item
:=
make
(
map
[
string
]
interface
{})
item
.
setValue
(
"log"
,
string
(
logs
[
i
]
.
Log
))
item
[
"ty"
]
=
logs
[
i
]
.
Ty
item
.
setValue
(
"format"
,
"proto"
)
item
[
"log"
]
=
string
(
logs
[
i
]
.
Log
)
obj
.
setValue
(
fmt
.
Sprint
(
i
),
item
)
item
[
"format"
]
=
"proto"
data
[
i
]
=
item
}
}
return
obj
.
value
()
return
data
}
}
func
accountReturn
(
vm
*
otto
.
Otto
,
acc
*
types
.
Account
)
otto
.
Value
{
func
accountReturn
(
vm
*
otto
.
Otto
,
acc
*
types
.
Account
)
otto
.
Value
{
...
...
plugin/dapp/js/executor/jsvm.go
View file @
7b849e3c
...
@@ -22,6 +22,7 @@ type blockContext struct {
...
@@ -22,6 +22,7 @@ type blockContext struct {
Difficulty
uint64
`json:"difficulty"`
Difficulty
uint64
`json:"difficulty"`
TxHash
string
`json:"txhash"`
TxHash
string
`json:"txhash"`
Index
int64
`json:"index"`
Index
int64
`json:"index"`
From
string
`json:"from"`
}
}
func
parseJsReturn
(
prefix
[]
byte
,
jsvalue
*
otto
.
Object
)
(
kvlist
[]
*
types
.
KeyValue
,
logs
[]
*
types
.
ReceiptLog
,
err
error
)
{
func
parseJsReturn
(
prefix
[]
byte
,
jsvalue
*
otto
.
Object
)
(
kvlist
[]
*
types
.
KeyValue
,
logs
[]
*
types
.
ReceiptLog
,
err
error
)
{
...
...
plugin/dapp/js/executor/jsvm_test.go
View file @
7b849e3c
...
@@ -22,12 +22,12 @@ func init() {
...
@@ -22,12 +22,12 @@ func init() {
Init
(
ptypes
.
JsX
,
nil
)
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
:=
newjs
()
.
(
*
js
)
e
.
SetEnv
(
1
,
time
.
Now
()
.
Unix
(),
1
)
e
.
SetEnv
(
1
,
time
.
Now
()
.
Unix
(),
1
)
e
.
SetLocalDB
(
kvdb
)
e
.
SetLocalDB
(
kvdb
)
e
.
SetStateDB
(
kvdb
)
e
.
SetStateDB
(
kvdb
)
c
,
tx
:=
createCodeTx
(
"test"
,
js
code
)
c
,
tx
:=
createCodeTx
(
"test"
,
code
)
receipt
,
err
:=
e
.
Exec_Create
(
c
,
tx
,
0
)
receipt
,
err
:=
e
.
Exec_Create
(
c
,
tx
,
0
)
assert
.
Nil
(
t
,
err
)
assert
.
Nil
(
t
,
err
)
util
.
SaveKVList
(
ldb
,
receipt
.
KV
)
util
.
SaveKVList
(
ldb
,
receipt
.
KV
)
...
@@ -54,7 +54,7 @@ func callCodeTx(name, f, args string) (*jsproto.Call, *types.Transaction) {
...
@@ -54,7 +54,7 @@ func callCodeTx(name, f, args string) (*jsproto.Call, *types.Transaction) {
func
TestCallcode
(
t
*
testing
.
T
)
{
func
TestCallcode
(
t
*
testing
.
T
)
{
dir
,
ldb
,
kvdb
:=
util
.
CreateTestDB
()
dir
,
ldb
,
kvdb
:=
util
.
CreateTestDB
()
defer
util
.
CloseTestDB
(
dir
,
ldb
)
defer
util
.
CloseTestDB
(
dir
,
ldb
)
e
:=
initExec
(
ldb
,
kvdb
,
t
)
e
:=
initExec
(
ldb
,
kvdb
,
jscode
,
t
)
call
,
tx
:=
callCodeTx
(
"test"
,
"hello"
,
`{"hello":"world"}`
)
call
,
tx
:=
callCodeTx
(
"test"
,
"hello"
,
`{"hello":"world"}`
)
receipt
,
err
:=
e
.
Exec_Call
(
call
,
tx
,
0
)
receipt
,
err
:=
e
.
Exec_Call
(
call
,
tx
,
0
)
...
@@ -107,7 +107,7 @@ func TestCallcode(t *testing.T) {
...
@@ -107,7 +107,7 @@ func TestCallcode(t *testing.T) {
func
TestCallError
(
t
*
testing
.
T
)
{
func
TestCallError
(
t
*
testing
.
T
)
{
dir
,
ldb
,
kvdb
:=
util
.
CreateTestDB
()
dir
,
ldb
,
kvdb
:=
util
.
CreateTestDB
()
defer
util
.
CloseTestDB
(
dir
,
ldb
)
defer
util
.
CloseTestDB
(
dir
,
ldb
)
e
:=
initExec
(
ldb
,
kvdb
,
t
)
e
:=
initExec
(
ldb
,
kvdb
,
jscode
,
t
)
//test call error(invalid json input)
//test call error(invalid json input)
call
,
tx
:=
callCodeTx
(
"test"
,
"hello"
,
`{hello":"world"}`
)
call
,
tx
:=
callCodeTx
(
"test"
,
"hello"
,
`{hello":"world"}`
)
_
,
err
:=
e
.
callVM
(
"exec"
,
call
,
tx
,
0
,
nil
)
_
,
err
:=
e
.
callVM
(
"exec"
,
call
,
tx
,
0
,
nil
)
...
@@ -132,7 +132,7 @@ func TestCallError(t *testing.T) {
...
@@ -132,7 +132,7 @@ func TestCallError(t *testing.T) {
func
TestBigInt
(
t
*
testing
.
T
)
{
func
TestBigInt
(
t
*
testing
.
T
)
{
dir
,
ldb
,
kvdb
:=
util
.
CreateTestDB
()
dir
,
ldb
,
kvdb
:=
util
.
CreateTestDB
()
defer
util
.
CloseTestDB
(
dir
,
ldb
)
defer
util
.
CloseTestDB
(
dir
,
ldb
)
e
:=
initExec
(
ldb
,
kvdb
,
t
)
e
:=
initExec
(
ldb
,
kvdb
,
jscode
,
t
)
//test call error(invalid json input)
//test call error(invalid json input)
s
:=
fmt
.
Sprintf
(
`{"balance":%d,"balance1":%d,"balance2":%d,"balance3":%d}`
,
math
.
MaxInt64
,
math
.
MinInt64
,
9007199254740990
,
-
9007199254740990
)
s
:=
fmt
.
Sprintf
(
`{"balance":%d,"balance1":%d,"balance2":%d,"balance3":%d}`
,
math
.
MaxInt64
,
math
.
MinInt64
,
9007199254740990
,
-
9007199254740990
)
call
,
tx
:=
callCodeTx
(
"test"
,
"hello"
,
s
)
call
,
tx
:=
callCodeTx
(
"test"
,
"hello"
,
s
)
...
@@ -146,7 +146,7 @@ func TestBigInt(t *testing.T) {
...
@@ -146,7 +146,7 @@ func TestBigInt(t *testing.T) {
func
BenchmarkBigInt
(
b
*
testing
.
B
)
{
func
BenchmarkBigInt
(
b
*
testing
.
B
)
{
dir
,
ldb
,
kvdb
:=
util
.
CreateTestDB
()
dir
,
ldb
,
kvdb
:=
util
.
CreateTestDB
()
defer
util
.
CloseTestDB
(
dir
,
ldb
)
defer
util
.
CloseTestDB
(
dir
,
ldb
)
e
:=
initExec
(
ldb
,
kvdb
,
b
)
e
:=
initExec
(
ldb
,
kvdb
,
jscode
,
b
)
//test call error(invalid json input)
//test call error(invalid json input)
s
:=
fmt
.
Sprintf
(
`{"balance":%d,"balance1":%d,"balance2":%d,"balance3":%d}`
,
math
.
MaxInt64
,
math
.
MinInt64
,
9007199254740990
,
-
9007199254740990
)
s
:=
fmt
.
Sprintf
(
`{"balance":%d,"balance1":%d,"balance2":%d,"balance3":%d}`
,
math
.
MaxInt64
,
math
.
MinInt64
,
9007199254740990
,
-
9007199254740990
)
call
,
tx
:=
callCodeTx
(
"test"
,
"hello"
,
s
)
call
,
tx
:=
callCodeTx
(
"test"
,
"hello"
,
s
)
...
@@ -184,7 +184,7 @@ func TestCalcLocalPrefix(t *testing.T) {
...
@@ -184,7 +184,7 @@ func TestCalcLocalPrefix(t *testing.T) {
func
TestCacheMemUsage
(
t
*
testing
.
T
)
{
func
TestCacheMemUsage
(
t
*
testing
.
T
)
{
dir
,
ldb
,
kvdb
:=
util
.
CreateTestDB
()
dir
,
ldb
,
kvdb
:=
util
.
CreateTestDB
()
defer
util
.
CloseTestDB
(
dir
,
ldb
)
defer
util
.
CloseTestDB
(
dir
,
ldb
)
e
:=
initExec
(
ldb
,
kvdb
,
t
)
e
:=
initExec
(
ldb
,
kvdb
,
jscode
,
t
)
vm
,
err
:=
e
.
createVM
(
"test"
,
nil
,
0
)
vm
,
err
:=
e
.
createVM
(
"test"
,
nil
,
0
)
assert
.
Nil
(
t
,
err
)
assert
.
Nil
(
t
,
err
)
vms
:=
make
([]
*
otto
.
Otto
,
1024
)
vms
:=
make
([]
*
otto
.
Otto
,
1024
)
...
...
plugin/dapp/js/executor/query.go
View file @
7b849e3c
...
@@ -4,10 +4,13 @@ import (
...
@@ -4,10 +4,13 @@ import (
"fmt"
"fmt"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/types"
ptypes
"github.com/33cn/plugin/plugin/dapp/js/types"
"github.com/33cn/plugin/plugin/dapp/js/types/jsproto"
"github.com/33cn/plugin/plugin/dapp/js/types/jsproto"
)
)
func
(
c
*
js
)
Query_Query
(
payload
*
jsproto
.
Call
)
(
types
.
Message
,
error
)
{
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
)
jsvalue
,
err
:=
c
.
callVM
(
"query"
,
payload
,
nil
,
0
,
nil
)
if
err
!=
nil
{
if
err
!=
nil
{
fmt
.
Println
(
"query"
,
err
)
fmt
.
Println
(
"query"
,
err
)
...
...
plugin/dapp/js/executor/rpc_test.go
View file @
7b849e3c
package
executor_test
package
executor_test
import
(
import
(
"encoding/json"
"fmt"
"math/rand"
"testing"
"testing"
"time"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/address"
rpctypes
"github.com/33cn/chain33/rpc/types"
rpctypes
"github.com/33cn/chain33/rpc/types"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util/testnode"
"github.com/33cn/chain33/util/testnode"
...
@@ -14,6 +20,10 @@ import (
...
@@ -14,6 +20,10 @@ import (
_
"github.com/33cn/plugin/plugin"
_
"github.com/33cn/plugin/plugin"
)
)
func
init
()
{
rand
.
Seed
(
time
.
Now
()
.
UnixNano
())
}
func
TestJsVM
(
t
*
testing
.
T
)
{
func
TestJsVM
(
t
*
testing
.
T
)
{
mocker
:=
testnode
.
New
(
"--free--"
,
nil
)
mocker
:=
testnode
.
New
(
"--free--"
,
nil
)
defer
mocker
.
Close
()
defer
mocker
.
Close
()
...
@@ -75,53 +85,204 @@ func TestJsVM(t *testing.T) {
...
@@ -75,53 +85,204 @@ func TestJsVM(t *testing.T) {
t
.
Log
(
queryresult
.
Data
)
t
.
Log
(
queryresult
.
Data
)
}
}
var
jscode
=
`
func
TestJsGame
(
t
*
testing
.
T
)
{
//数据结构设计
contractName
:=
"test1"
//kvlist [{key:"key1", value:"value1"},{key:"key2", value:"value2"}]
mocker
:=
testnode
.
New
(
"--free--"
,
nil
)
//log 设计 {json data}
defer
mocker
.
Close
()
function Init(context) {
mocker
.
Listen
()
this.kvc = new kvcreator("init")
err
:=
mocker
.
SendHot
()
this.context = context
assert
.
Nil
(
t
,
err
)
this.kvc.add("action", "init")
//开始部署合约, 测试阶段任何人都可以部署合约
this.kvc.add("context", this.context)
//后期需要加上权限控制
return this.kvc.receipt()
//1. 部署合约
}
create
:=
&
jsproto
.
Create
{
Code
:
gamecode
,
function Exec(context) {
Name
:
contractName
,
this.kvc = new kvcreator("exec")
}
this.context = context
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
)
function ExecLocal(context, logs) {
reqtx
=
&
rpctypes
.
CreateTx
{
this.kvc = new kvcreator("local")
To
:
address
.
ExecAddress
(
"user.jsvm."
+
contractName
),
this.context = context
Amount
:
100
*
types
.
Coin
,
this.logs = logs
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
.
GetGenesisKey
(),
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
.
GetGenesisAddress
())
.
Balance
assert
.
Equal
(
t
,
100
*
types
.
Coin
,
balance
)
t
.
Log
(
mocker
.
GetGenesisAddress
())
//2.2 调用 hello 函数(随机数,用nonce)
privhash
:=
common
.
Sha256
(
mocker
.
GetHotKey
()
.
Bytes
())
nonce
:=
rand
.
Int63
()
num
:=
rand
.
Int63
()
%
10
realhash
:=
common
.
ToHex
(
common
.
Sha256
([]
byte
(
string
(
privhash
)
+
":"
+
fmt
.
Sprint
(
nonce
))))
myhash
:=
common
.
ToHex
(
common
.
Sha256
([]
byte
(
realhash
+
fmt
.
Sprint
(
num
))))
function Query(context) {
call
:=
&
jsproto
.
Call
{
this.kvc = new kvcreator("query")
Funcname
:
"NewGame"
,
this.context = context
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
)
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
))
gameid
:=
txinfo
.
Height
*
100000
+
txinfo
.
Index
//2.3 guess a number (win)
call
=
&
jsproto
.
Call
{
Funcname
:
"Guess"
,
Name
:
contractName
,
Args
:
fmt
.
Sprintf
(
`{"bet": %d, "gameid" : "%d", "num" : %d}`
,
1
*
types
.
Coin
,
gameid
,
num
),
}
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
)
hash
,
err
=
mocker
.
SendAndSignNonce
(
mocker
.
GetGenesisKey
(),
txhex
,
nonce
)
assert
.
Nil
(
t
,
err
)
txinfo
,
err
=
mocker
.
WaitTx
(
hash
)
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
txinfo
.
Receipt
.
Ty
,
int32
(
2
))
Exec.prototype.hello = function(args) {
//2.4 guess a num (failed)
this.kvc.add("args", args)
call
=
&
jsproto
.
Call
{
this.kvc.add("action", "exec")
Funcname
:
"Guess"
,
this.kvc.add("context", this.context)
Name
:
contractName
,
this.kvc.addlog({"key1": "value1"})
Args
:
fmt
.
Sprintf
(
`{"bet": %d, "gameid" : "%d", "num" : %d}`
,
1
*
types
.
Coin
,
gameid
,
num
+
1
),
this.kvc.addlog({"key2": "value2"})
}
return this.kvc.receipt()
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
.
GetGenesisKey
(),
txhex
,
nonce
)
assert
.
Nil
(
t
,
err
)
txinfo
,
err
=
mocker
.
WaitTx
(
hash
)
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
txinfo
.
Receipt
.
Ty
,
int32
(
2
))
ExecLocal.prototype.hello = function(args) {
//2.5 close the game
this.kvc.add("args", args)
call
=
&
jsproto
.
Call
{
this.kvc.add("action", "execlocal")
Funcname
:
"CloseGame"
,
this.kvc.add("log", this.logs)
Name
:
contractName
,
this.kvc.add("context", this.context)
Args
:
fmt
.
Sprintf
(
`{"gameid":%d, "randstr":"%s"}`
,
gameid
,
realhash
),
return this.kvc.receipt()
}
}
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
))
//3.1 query game 函数查询
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
)
//return a json string
//3.2 query match -> status 函数
Query.prototype.hello = function(args) {
call
=
&
jsproto
.
Call
{
return tojson({hello:"wzw"})
Funcname
:
"JoinKey"
,
Name
:
contractName
,
Args
:
fmt
.
Sprintf
(
`{"left":"%s", "right" : "%s"}`
,
mocker
.
GetGenesisAddress
(),
"2"
),
}
query
=
&
rpctypes
.
Query4Jrpc
{
Execer
:
"user."
+
ptypes
.
JsX
+
"."
+
contractName
,
FuncName
:
"Query"
,
Payload
:
types
.
MustPBToJSON
(
call
),
}
err
=
mocker
.
GetJSONC
()
.
Call
(
"Chain33.Query"
,
query
,
&
queryresult
)
assert
.
Nil
(
t
,
err
)
joinkey
:=
queryresult
.
Data
reqjson
:=
make
(
map
[
string
]
interface
{})
reqjson
[
"addr#status"
]
=
joinkey
reqdata
,
_
:=
json
.
Marshal
(
reqjson
)
call
=
&
jsproto
.
Call
{
Funcname
:
"ListMatchByAddr"
,
Name
:
contractName
,
Args
:
string
(
reqdata
),
}
query
=
&
rpctypes
.
Query4Jrpc
{
Execer
:
"user."
+
ptypes
.
JsX
+
"."
+
contractName
,
FuncName
:
"Query"
,
Payload
:
types
.
MustPBToJSON
(
call
),
}
err
=
mocker
.
GetJSONC
()
.
Call
(
"Chain33.Query"
,
query
,
&
queryresult
)
assert
.
Nil
(
t
,
err
)
t
.
Log
(
queryresult
.
Data
)
}
}
`
plugin/dapp/js/executor/runtime.go
View file @
7b849e3c
package
executor
package
executor
import
(
import
(
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/common/address"
"github.com/robertkrimen/otto"
"github.com/robertkrimen/otto"
)
)
...
@@ -17,6 +18,17 @@ func execaddressFunc(vm *otto.Otto) {
...
@@ -17,6 +18,17 @@ func execaddressFunc(vm *otto.Otto) {
})
})
}
}
func
sha256Func
(
vm
*
otto
.
Otto
)
{
vm
.
Set
(
"sha256"
,
func
(
call
otto
.
FunctionCall
)
otto
.
Value
{
key
,
err
:=
call
.
Argument
(
0
)
.
ToString
()
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
}
var
hash
=
common
.
Sha256
([]
byte
(
key
))
return
okReturn
(
vm
,
common
.
ToHex
(
hash
))
})
}
/*
/*
//获取系统随机数的接口
//获取系统随机数的接口
//randnum
//randnum
...
...
plugin/dapp/js/executor/runtime.js
View file @
7b849e3c
var
tojson
=
JSON
.
stringify
var
tojson
=
JSON
.
stringify
//table warp
//table warp
function
t
able
(
kvc
,
config
,
defaultvalue
)
{
function
T
able
(
kvc
,
config
,
defaultvalue
)
{
var
ret
=
table_new
(
config
,
defaultvalue
)
var
ret
=
table_new
(
tojson
(
config
),
tojson
(
defaultvalue
)
)
if
(
ret
.
err
)
{
if
(
ret
.
err
)
{
throw
new
Error
(
ret
.
err
)
throw
new
Error
(
ret
.
err
)
}
}
this
.
kvc
=
kvc
this
.
kvc
=
kvc
this
.
id
=
ret
.
id
this
.
id
=
ret
.
id
this
.
config
=
config
this
.
config
=
config
this
.
name
=
config
[
"#tablename"
]
this
.
defaultvalue
=
defaultvalue
this
.
defaultvalue
=
defaultvalue
}
}
...
@@ -15,7 +16,7 @@ function isstring(obj) {
...
@@ -15,7 +16,7 @@ function isstring(obj) {
return
typeof
obj
===
"string"
return
typeof
obj
===
"string"
}
}
t
able
.
prototype
.
add
=
function
(
obj
)
{
T
able
.
prototype
.
add
=
function
(
obj
)
{
if
(
!
isstring
(
obj
))
{
if
(
!
isstring
(
obj
))
{
obj
=
tojson
(
obj
)
obj
=
tojson
(
obj
)
}
}
...
@@ -23,7 +24,57 @@ table.prototype.add = function(obj) {
...
@@ -23,7 +24,57 @@ table.prototype.add = function(obj) {
return
ret
.
err
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
)
{
if
(
!
isstring
(
row
))
{
row
=
tojson
(
row
)
}
var
ret
=
table_get
(
this
.
id
,
key
,
row
)
if
(
ret
.
err
)
{
throwerr
(
ret
.
err
)
}
return
ret
.
value
}
function
query_list
(
indexName
,
prefix
,
primaryKey
,
count
,
direction
)
{
if
(
count
!==
0
&&
!
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
)
if
(
q
.
err
)
{
return
null
}
for
(
var
i
=
0
;
i
<
q
.
length
;
i
++
)
{
if
(
q
[
i
].
left
)
{
q
[
i
].
left
=
JSON
.
parse
(
q
[
i
].
left
)
}
if
(
q
[
i
].
right
)
{
q
[
i
].
right
=
JSON
.
parse
(
q
[
i
].
right
)
}
}
return
q
}
Table
.
prototype
.
query
=
function
(
indexName
,
prefix
,
primaryKey
,
count
,
direction
)
{
return
query_list
.
call
(
this
,
indexName
,
prefix
,
primaryKey
,
count
,
direction
)
}
Table
.
prototype
.
replace
=
function
(
obj
)
{
if
(
!
isstring
(
obj
))
{
if
(
!
isstring
(
obj
))
{
obj
=
tojson
(
obj
)
obj
=
tojson
(
obj
)
}
}
...
@@ -31,7 +82,7 @@ table.prototype.replace = function(obj) {
...
@@ -31,7 +82,7 @@ table.prototype.replace = function(obj) {
return
ret
.
err
return
ret
.
err
}
}
t
able
.
prototype
.
del
=
function
(
obj
)
{
T
able
.
prototype
.
del
=
function
(
obj
)
{
if
(
!
isstring
(
obj
))
{
if
(
!
isstring
(
obj
))
{
obj
=
tojson
(
obj
)
obj
=
tojson
(
obj
)
}
}
...
@@ -39,7 +90,7 @@ table.prototype.del = function(obj) {
...
@@ -39,7 +90,7 @@ table.prototype.del = function(obj) {
return
ret
.
err
return
ret
.
err
}
}
t
able
.
prototype
.
save
=
function
()
{
T
able
.
prototype
.
save
=
function
()
{
var
ret
=
table_save
(
this
.
id
)
var
ret
=
table_save
(
this
.
id
)
if
(
!
this
.
kvc
)
{
if
(
!
this
.
kvc
)
{
this
.
kvc
.
save
(
ret
)
this
.
kvc
.
save
(
ret
)
...
@@ -47,17 +98,17 @@ table.prototype.save = function() {
...
@@ -47,17 +98,17 @@ table.prototype.save = function() {
return
ret
return
ret
}
}
t
able
.
prototype
.
close
=
function
()
{
T
able
.
prototype
.
close
=
function
()
{
var
ret
=
table_close
(
this
.
id
)
var
ret
=
table_close
(
this
.
id
)
return
ret
.
err
return
ret
.
err
}
}
function
JoinTable
(
lefttable
,
righttable
,
index
)
{
function
JoinTable
(
lefttable
,
righttable
,
index
)
{
this
.
lefttable
=
lefttable
this
.
righttable
=
righttable
if
(
this
.
lefttable
.
kvc
!=
this
.
righttable
.
kvc
)
{
if
(
this
.
lefttable
.
kvc
!=
this
.
righttable
.
kvc
)
{
throw
new
Error
(
"the kvc of left and right must same"
)
throw
new
Error
(
"the kvc of left and right must same"
)
}
}
this
.
lefttable
=
lefttable
this
.
righttable
=
righttable
this
.
index
=
index
this
.
index
=
index
var
ret
=
new_join_table
(
this
.
lefttable
.
id
,
this
.
righttable
.
id
,
index
)
var
ret
=
new_join_table
(
this
.
lefttable
.
id
,
this
.
righttable
.
id
,
index
)
if
(
ret
.
err
)
{
if
(
ret
.
err
)
{
...
@@ -67,14 +118,44 @@ function JoinTable(lefttable, righttable, index) {
...
@@ -67,14 +118,44 @@ function JoinTable(lefttable, righttable, index) {
this
.
kvc
=
this
.
lefttable
.
kvc
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
)
var
ret
=
table_save
(
this
.
id
)
if
(
!
this
.
kvc
)
{
if
(
this
.
kvc
)
{
this
.
kvc
.
save
(
ret
)
this
.
kvc
.
save
(
ret
)
}
}
return
ret
return
ret
}
}
JoinTable
.
prototype
.
get
=
function
(
key
,
row
)
{
if
(
!
isstring
(
row
))
{
row
=
tojson
(
row
)
}
var
ret
=
table_get
(
this
.
id
,
key
,
row
)
if
(
ret
.
err
)
{
throwerr
(
ret
.
err
)
}
return
ret
.
value
}
JoinTable
.
prototype
.
query
=
function
(
indexName
,
prefix
,
primaryKey
,
count
,
direction
)
{
return
query_list
.
call
(
this
,
indexName
,
prefix
,
primaryKey
,
count
,
direction
)
}
function
querytojson
(
data
)
{
if
(
!
data
)
{
return
"[]"
}
return
tojson
(
data
)
}
JoinTable
.
prototype
.
close
=
function
()
{
JoinTable
.
prototype
.
close
=
function
()
{
table_close
(
this
.
lefttable
.
id
)
table_close
(
this
.
lefttable
.
id
)
table_close
(
this
.
righttable
.
id
)
table_close
(
this
.
righttable
.
id
)
...
@@ -82,6 +163,24 @@ JoinTable.prototype.close = function() {
...
@@ -82,6 +163,24 @@ JoinTable.prototype.close = function() {
return
ret
.
err
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
//account warp
function
account
(
kvc
,
execer
,
symbol
)
{
function
account
(
kvc
,
execer
,
symbol
)
{
this
.
execer
=
execer
this
.
execer
=
execer
...
@@ -91,7 +190,7 @@ function account(kvc, execer, symbol) {
...
@@ -91,7 +190,7 @@ function account(kvc, execer, symbol) {
account
.
prototype
.
genesisInit
=
function
(
addr
,
amount
)
{
account
.
prototype
.
genesisInit
=
function
(
addr
,
amount
)
{
var
ret
=
genesis_init
(
this
,
addr
,
amount
)
var
ret
=
genesis_init
(
this
,
addr
,
amount
)
if
(
!
this
.
kvc
)
{
if
(
this
.
kvc
)
{
this
.
kvc
.
save
(
ret
)
this
.
kvc
.
save
(
ret
)
}
}
return
ret
.
err
return
ret
.
err
...
@@ -99,7 +198,7 @@ account.prototype.genesisInit = function(addr, amount) {
...
@@ -99,7 +198,7 @@ account.prototype.genesisInit = function(addr, amount) {
account
.
prototype
.
execGenesisInit
=
function
(
execer
,
addr
,
amount
)
{
account
.
prototype
.
execGenesisInit
=
function
(
execer
,
addr
,
amount
)
{
var
ret
=
genesis_init_exec
(
this
,
execer
,
addr
,
amount
)
var
ret
=
genesis_init_exec
(
this
,
execer
,
addr
,
amount
)
if
(
!
this
.
kvc
)
{
if
(
this
.
kvc
)
{
this
.
kvc
.
save
(
ret
)
this
.
kvc
.
save
(
ret
)
}
}
return
ret
.
err
return
ret
.
err
...
@@ -116,7 +215,7 @@ account.prototype.execGetBalance = function(execer, addr) {
...
@@ -116,7 +215,7 @@ account.prototype.execGetBalance = function(execer, addr) {
//本合约转移资产,或者转移到其他合约,或者从其他合约取回资产
//本合约转移资产,或者转移到其他合约,或者从其他合约取回资产
account
.
prototype
.
transfer
=
function
(
from
,
to
,
amount
)
{
account
.
prototype
.
transfer
=
function
(
from
,
to
,
amount
)
{
var
ret
=
transfer
(
this
,
from
,
to
,
amount
)
var
ret
=
transfer
(
this
,
from
,
to
,
amount
)
if
(
!
this
.
kvc
)
{
if
(
this
.
kvc
)
{
this
.
kvc
.
save
(
ret
)
this
.
kvc
.
save
(
ret
)
}
}
return
ret
.
err
return
ret
.
err
...
@@ -124,7 +223,7 @@ account.prototype.transfer = function(from, to, amount) {
...
@@ -124,7 +223,7 @@ account.prototype.transfer = function(from, to, amount) {
account
.
prototype
.
transferToExec
=
function
(
execer
,
from
,
amount
)
{
account
.
prototype
.
transferToExec
=
function
(
execer
,
from
,
amount
)
{
var
ret
=
transfer_to_exec
(
this
,
execer
,
from
,
amount
)
var
ret
=
transfer_to_exec
(
this
,
execer
,
from
,
amount
)
if
(
!
this
.
kvc
)
{
if
(
this
.
kvc
)
{
this
.
kvc
.
save
(
ret
)
this
.
kvc
.
save
(
ret
)
}
}
return
ret
.
err
return
ret
.
err
...
@@ -132,7 +231,7 @@ account.prototype.transferToExec = function(execer, from, amount) {
...
@@ -132,7 +231,7 @@ account.prototype.transferToExec = function(execer, from, amount) {
account
.
prototype
.
withdrawFromExec
=
function
(
execer
,
to
,
amount
)
{
account
.
prototype
.
withdrawFromExec
=
function
(
execer
,
to
,
amount
)
{
var
ret
=
withdraw
(
this
,
execer
,
to
,
amount
)
var
ret
=
withdraw
(
this
,
execer
,
to
,
amount
)
if
(
!
this
.
kvc
)
{
if
(
this
.
kvc
)
{
this
.
kvc
.
save
(
ret
)
this
.
kvc
.
save
(
ret
)
}
}
return
ret
.
err
return
ret
.
err
...
@@ -141,7 +240,7 @@ account.prototype.withdrawFromExec = function(execer, to, amount) {
...
@@ -141,7 +240,7 @@ account.prototype.withdrawFromExec = function(execer, to, amount) {
//管理其他合约的资产转移到这个合约中
//管理其他合约的资产转移到这个合约中
account
.
prototype
.
execActive
=
function
(
execer
,
addr
,
amount
)
{
account
.
prototype
.
execActive
=
function
(
execer
,
addr
,
amount
)
{
var
ret
=
exec_active
(
this
,
execer
,
addr
,
amount
)
var
ret
=
exec_active
(
this
,
execer
,
addr
,
amount
)
if
(
!
this
.
kvc
)
{
if
(
this
.
kvc
)
{
this
.
kvc
.
save
(
ret
)
this
.
kvc
.
save
(
ret
)
}
}
return
ret
.
err
return
ret
.
err
...
@@ -149,7 +248,7 @@ account.prototype.execActive = function(execer, addr, amount) {
...
@@ -149,7 +248,7 @@ account.prototype.execActive = function(execer, addr, amount) {
account
.
prototype
.
execFrozen
=
function
(
execer
,
addr
,
amount
)
{
account
.
prototype
.
execFrozen
=
function
(
execer
,
addr
,
amount
)
{
var
ret
=
exec_frozen
(
this
,
execer
,
addr
,
amount
)
var
ret
=
exec_frozen
(
this
,
execer
,
addr
,
amount
)
if
(
!
this
.
kvc
)
{
if
(
this
.
kvc
)
{
this
.
kvc
.
save
(
ret
)
this
.
kvc
.
save
(
ret
)
}
}
return
ret
.
err
return
ret
.
err
...
@@ -157,7 +256,7 @@ account.prototype.execFrozen = function(execer, addr, amount) {
...
@@ -157,7 +256,7 @@ account.prototype.execFrozen = function(execer, addr, amount) {
account
.
prototype
.
execDeposit
=
function
(
execer
,
addr
,
amount
)
{
account
.
prototype
.
execDeposit
=
function
(
execer
,
addr
,
amount
)
{
var
ret
=
exec_deposit
(
this
,
execer
,
addr
,
amount
)
var
ret
=
exec_deposit
(
this
,
execer
,
addr
,
amount
)
if
(
!
this
.
kvc
)
{
if
(
this
.
kvc
)
{
this
.
kvc
.
save
(
ret
)
this
.
kvc
.
save
(
ret
)
}
}
return
ret
.
err
return
ret
.
err
...
@@ -165,7 +264,7 @@ account.prototype.execDeposit = function(execer, addr, amount) {
...
@@ -165,7 +264,7 @@ account.prototype.execDeposit = function(execer, addr, amount) {
account
.
prototype
.
execWithdraw
=
function
(
execer
,
addr
,
amount
)
{
account
.
prototype
.
execWithdraw
=
function
(
execer
,
addr
,
amount
)
{
var
ret
=
exec_withdraw
(
this
,
execer
,
addr
,
amount
)
var
ret
=
exec_withdraw
(
this
,
execer
,
addr
,
amount
)
if
(
!
this
.
kvc
)
{
if
(
this
.
kvc
)
{
this
.
kvc
.
save
(
ret
)
this
.
kvc
.
save
(
ret
)
}
}
return
ret
.
err
return
ret
.
err
...
@@ -173,12 +272,47 @@ account.prototype.execWithdraw = function(execer, addr, amount) {
...
@@ -173,12 +272,47 @@ account.prototype.execWithdraw = function(execer, addr, amount) {
account
.
prototype
.
execTransfer
=
function
(
execer
,
from
,
to
,
amount
)
{
account
.
prototype
.
execTransfer
=
function
(
execer
,
from
,
to
,
amount
)
{
var
ret
=
exec_transfer
(
this
,
execer
,
from
,
to
,
amount
)
var
ret
=
exec_transfer
(
this
,
execer
,
from
,
to
,
amount
)
if
(
!
this
.
kvc
)
{
if
(
this
.
kvc
)
{
this
.
kvc
.
save
(
ret
)
this
.
kvc
.
save
(
ret
)
}
}
return
ret
.
err
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
}
err
=
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
)
{
function
kvcreator
(
dbtype
)
{
this
.
data
=
{}
this
.
data
=
{}
this
.
kvs
=
[]
this
.
kvs
=
[]
...
@@ -188,11 +322,11 @@ function kvcreator(dbtype) {
...
@@ -188,11 +322,11 @@ function kvcreator(dbtype) {
this
.
getloal
=
getlocaldb
this
.
getloal
=
getlocaldb
this
.
list
=
listdb
this
.
list
=
listdb
if
(
dbtype
==
"exec"
||
dbtype
==
"init"
)
{
if
(
dbtype
==
"exec"
||
dbtype
==
"init"
)
{
this
.
get
=
this
.
getstatedb
this
.
get
db
=
this
.
getstate
}
else
if
(
dbtype
==
"local"
)
{
}
else
if
(
dbtype
==
"local"
)
{
this
.
get
=
this
.
getlocaldb
this
.
get
db
=
this
.
getlocal
}
else
if
(
dbtype
==
"query"
)
{
}
else
if
(
dbtype
==
"query"
)
{
this
.
get
=
this
.
getlocaldb
this
.
get
db
=
this
.
getlocal
}
else
{
}
else
{
throw
new
Error
(
"chain33.js: dbtype error"
)
throw
new
Error
(
"chain33.js: dbtype error"
)
}
}
...
@@ -211,8 +345,8 @@ kvcreator.prototype.get = function(k, prefix) {
...
@@ -211,8 +345,8 @@ kvcreator.prototype.get = function(k, prefix) {
if
(
this
.
data
[
k
])
{
if
(
this
.
data
[
k
])
{
v
=
this
.
data
[
k
]
v
=
this
.
data
[
k
]
}
else
{
}
else
{
var
dbvalue
=
this
.
get
(
k
,
!!
prefix
)
var
dbvalue
=
this
.
getdb
(
k
,
!!
prefix
)
if
(
dbvalue
.
err
!=
""
)
{
if
(
dbvalue
.
err
)
{
return
null
return
null
}
}
v
=
dbvalue
.
value
v
=
dbvalue
.
value
...
@@ -240,7 +374,7 @@ kvcreator.prototype.save = function(receipt) {
...
@@ -240,7 +374,7 @@ kvcreator.prototype.save = function(receipt) {
kvcreator
.
prototype
.
listvalue
=
function
(
prefix
,
key
,
count
,
direction
)
{
kvcreator
.
prototype
.
listvalue
=
function
(
prefix
,
key
,
count
,
direction
)
{
var
dbvalues
=
this
.
list
(
prefix
,
key
,
count
,
direction
)
var
dbvalues
=
this
.
list
(
prefix
,
key
,
count
,
direction
)
if
(
dbvalues
.
err
!=
""
)
{
if
(
dbvalues
.
err
)
{
return
[]
return
[]
}
}
var
values
=
dbvalues
.
value
var
values
=
dbvalues
.
value
...
@@ -274,6 +408,73 @@ kvcreator.prototype.receipt = function() {
...
@@ -274,6 +408,73 @@ kvcreator.prototype.receipt = function() {
return
{
kvs
:
this
.
kvs
,
logs
:
this
.
logs
}
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
)
}
}
Query
.
prototype
.
JoinKey
=
function
(
args
)
{
return
table_joinkey
(
args
.
left
,
args
.
right
).
value
}
function
throwerr
(
err
,
msg
)
{
if
(
err
)
{
throw
new
Error
(
err
+
":"
+
msg
)
}
}
function
callcode
(
context
,
f
,
args
,
loglist
)
{
function
callcode
(
context
,
f
,
args
,
loglist
)
{
if
(
f
==
"init"
)
{
if
(
f
==
"init"
)
{
return
Init
(
JSON
.
parse
(
context
))
return
Init
(
JSON
.
parse
(
context
))
...
@@ -303,7 +504,7 @@ function callcode(context, f, args, loglist) {
...
@@ -303,7 +504,7 @@ function callcode(context, f, args, loglist) {
}
}
var
arg
=
JSON
.
parse
(
args
)
var
arg
=
JSON
.
parse
(
args
)
if
(
typeof
runobj
[
funcname
]
!=
"function"
)
{
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
)
return
runobj
[
funcname
](
arg
)
}
}
...
...
plugin/dapp/js/executor/table.go
View file @
7b849e3c
package
executor
package
executor
import
(
import
(
"bytes"
"encoding/json"
"encoding/json"
"errors"
"fmt"
"fmt"
"regexp"
"strconv"
"strings"
"strings"
"sync"
"sync/atomic"
"github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/db/table"
"github.com/33cn/chain33/common/db/table"
...
@@ -34,22 +36,11 @@ import (
...
@@ -34,22 +36,11 @@ import (
"index2" : "",
"index2" : "",
}
}
*/
*/
var
globalTableHandle
sync
.
Map
var
globalHanldeID
int64
//NewTable 创建一个新的表格, 返回handle
//NewTable 创建一个新的表格, 返回handle
func
(
u
*
js
)
newTable
(
name
,
config
,
defaultvalue
string
)
(
id
int64
,
err
error
)
{
func
(
u
*
js
)
newTable
(
name
,
config
,
defaultvalue
string
)
(
id
int64
,
err
error
)
{
for
{
u
.
globalHanldeID
++
id
=
atomic
.
AddInt64
(
&
globalHanldeID
,
1
)
%
maxjsint
id
=
u
.
globalHanldeID
if
_
,
ok
:=
globalTableHandle
.
Load
(
id
);
ok
{
continue
}
if
id
<
0
{
atomic
.
StoreInt64
(
&
globalHanldeID
,
0
)
continue
}
break
}
row
,
err
:=
NewJSONRow
(
config
,
defaultvalue
)
row
,
err
:=
NewJSONRow
(
config
,
defaultvalue
)
if
err
!=
nil
{
if
err
!=
nil
{
return
0
,
err
return
0
,
err
...
@@ -73,7 +64,7 @@ func (u *js) newTable(name, config, defaultvalue string) (id int64, err error) {
...
@@ -73,7 +64,7 @@ func (u *js) newTable(name, config, defaultvalue string) (id int64, err error) {
indexs
=
append
(
indexs
,
k
)
indexs
=
append
(
indexs
,
k
)
}
}
opt
:=
&
table
.
Option
{
opt
:=
&
table
.
Option
{
Prefix
:
string
(
prefix
),
Prefix
:
string
s
.
Trim
(
string
(
prefix
),
"-"
),
Name
:
row
.
config
[
"#tablename"
],
Name
:
row
.
config
[
"#tablename"
],
Primary
:
row
.
config
[
"#primary"
],
Primary
:
row
.
config
[
"#primary"
],
Index
:
indexs
,
Index
:
indexs
,
...
@@ -82,7 +73,7 @@ func (u *js) newTable(name, config, defaultvalue string) (id int64, err error) {
...
@@ -82,7 +73,7 @@ func (u *js) newTable(name, config, defaultvalue string) (id int64, err error) {
if
err
!=
nil
{
if
err
!=
nil
{
return
0
,
err
return
0
,
err
}
}
globalTableHandle
.
Store
(
id
,
t
)
u
.
globalTableHandle
.
Store
(
id
,
t
)
return
id
,
nil
return
id
,
nil
}
}
...
@@ -105,45 +96,64 @@ func (u *js) newTableFunc(vm *otto.Otto, name string) {
...
@@ -105,45 +96,64 @@ func (u *js) newTableFunc(vm *otto.Otto, name string) {
}
}
//CloseTable 关闭表格释放内存
//CloseTable 关闭表格释放内存
func
closeTable
(
id
int64
)
error
{
func
(
u
*
js
)
closeTable
(
id
int64
)
error
{
_
,
ok
:=
globalTableHandle
.
Load
(
id
)
_
,
ok
:=
u
.
globalTableHandle
.
Load
(
id
)
if
!
ok
{
if
!
ok
{
return
types
.
ErrNotFound
return
types
.
ErrNotFound
}
}
globalTableHandle
.
Delete
(
id
)
u
.
globalTableHandle
.
Delete
(
id
)
return
nil
return
nil
}
}
func
getTable
(
id
int64
)
(
*
table
.
Table
,
error
)
{
func
(
u
*
js
)
getTable
(
id
int64
)
(
*
table
.
Table
,
error
)
{
if
value
,
ok
:=
globalTableHandle
.
Load
(
id
);
ok
{
if
value
,
ok
:=
u
.
globalTableHandle
.
Load
(
id
);
ok
{
return
value
.
(
*
table
.
Table
),
nil
return
value
.
(
*
table
.
Table
),
nil
}
}
return
nil
,
types
.
ErrNotFound
return
nil
,
types
.
ErrNotFound
}
}
func
getSaver
(
id
int64
)
(
sav
er
,
error
)
{
func
(
u
*
js
)
getTabler
(
id
int64
)
(
tabl
er
,
error
)
{
if
value
,
ok
:=
globalTableHandle
.
Load
(
id
);
ok
{
if
value
,
ok
:=
u
.
globalTableHandle
.
Load
(
id
);
ok
{
return
value
.
(
sav
er
),
nil
return
value
.
(
tabl
er
),
nil
}
}
return
nil
,
types
.
ErrNotFound
return
nil
,
types
.
ErrNotFound
}
}
func
registerTableFunc
(
vm
*
otto
.
Otto
)
{
func
(
u
*
js
)
registerTableFunc
(
vm
*
otto
.
Otto
,
name
string
)
{
tableAddFunc
(
vm
)
u
.
newTableFunc
(
vm
,
name
)
tableReplaceFunc
(
vm
)
u
.
tableAddFunc
(
vm
)
tableDelFunc
(
vm
)
u
.
tableReplaceFunc
(
vm
)
tableCloseFunc
(
vm
)
u
.
tableDelFunc
(
vm
)
tableSave
(
vm
)
u
.
tableCloseFunc
(
vm
)
tableJoinFunc
(
vm
)
u
.
tableSave
(
vm
)
u
.
tableJoinFunc
(
vm
)
u
.
tableQueryFunc
(
vm
)
u
.
tableGetFunc
(
vm
)
u
.
tableJoinKeyFunc
(
vm
)
}
}
func
tableAddFunc
(
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
{
return
errReturn
(
vm
,
err
)
}
right
,
err
:=
call
.
Argument
(
1
)
.
ToString
()
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
}
key
:=
table
.
JoinKey
([]
byte
(
left
),
[]
byte
(
right
))
return
okReturn
(
vm
,
string
(
key
))
})
}
func
(
u
*
js
)
tableAddFunc
(
vm
*
otto
.
Otto
)
{
vm
.
Set
(
"table_add"
,
func
(
call
otto
.
FunctionCall
)
otto
.
Value
{
vm
.
Set
(
"table_add"
,
func
(
call
otto
.
FunctionCall
)
otto
.
Value
{
id
,
err
:=
call
.
Argument
(
0
)
.
ToInteger
()
id
,
err
:=
call
.
Argument
(
0
)
.
ToInteger
()
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
tab
,
err
:=
getTable
(
id
)
tab
,
err
:=
u
.
getTable
(
id
)
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
...
@@ -159,13 +169,13 @@ func tableAddFunc(vm *otto.Otto) {
...
@@ -159,13 +169,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
{
vm
.
Set
(
"table_replace"
,
func
(
call
otto
.
FunctionCall
)
otto
.
Value
{
id
,
err
:=
call
.
Argument
(
0
)
.
ToInteger
()
id
,
err
:=
call
.
Argument
(
0
)
.
ToInteger
()
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
tab
,
err
:=
getTable
(
id
)
tab
,
err
:=
u
.
getTable
(
id
)
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
...
@@ -181,13 +191,13 @@ func tableReplaceFunc(vm *otto.Otto) {
...
@@ -181,13 +191,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
{
vm
.
Set
(
"table_del"
,
func
(
call
otto
.
FunctionCall
)
otto
.
Value
{
id
,
err
:=
call
.
Argument
(
0
)
.
ToInteger
()
id
,
err
:=
call
.
Argument
(
0
)
.
ToInteger
()
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
tab
,
err
:=
getTable
(
id
)
tab
,
err
:=
u
.
getTable
(
id
)
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
...
@@ -203,17 +213,47 @@ func tableDelFunc(vm *otto.Otto) {
...
@@ -203,17 +213,47 @@ func tableDelFunc(vm *otto.Otto) {
})
})
}
}
type
saver
interface
{
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
:=
u
.
getTable
(
id
)
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
}
key
,
err
:=
call
.
Argument
(
1
)
.
ToString
()
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
}
row
,
err
:=
call
.
Argument
(
2
)
.
ToString
()
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
}
meta
:=
tab
.
GetMeta
()
meta
.
SetPayload
(
&
jsproto
.
JsLog
{
Data
:
row
})
result
,
err
:=
meta
.
Get
(
key
)
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
}
return
okReturn
(
vm
,
string
(
result
))
})
}
type
tabler
interface
{
GetMeta
()
table
.
RowMeta
ListIndex
(
indexName
string
,
prefix
[]
byte
,
primaryKey
[]
byte
,
count
,
direction
int32
)
(
rows
[]
*
table
.
Row
,
err
error
)
Save
()
(
kvs
[]
*
types
.
KeyValue
,
err
error
)
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
{
vm
.
Set
(
"table_save"
,
func
(
call
otto
.
FunctionCall
)
otto
.
Value
{
id
,
err
:=
call
.
Argument
(
0
)
.
ToInteger
()
id
,
err
:=
call
.
Argument
(
0
)
.
ToInteger
()
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
tab
,
err
:=
getSav
er
(
id
)
tab
,
err
:=
u
.
getTabl
er
(
id
)
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
...
@@ -225,13 +265,13 @@ func tableSave(vm *otto.Otto) {
...
@@ -225,13 +265,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
{
vm
.
Set
(
"table_close"
,
func
(
call
otto
.
FunctionCall
)
otto
.
Value
{
id
,
err
:=
call
.
Argument
(
0
)
.
ToInteger
()
id
,
err
:=
call
.
Argument
(
0
)
.
ToInteger
()
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
err
=
closeTable
(
id
)
err
=
u
.
closeTable
(
id
)
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
...
@@ -239,13 +279,95 @@ func tableCloseFunc(vm *otto.Otto) {
...
@@ -239,13 +279,95 @@ func tableCloseFunc(vm *otto.Otto) {
})
})
}
}
func
tableJoinFunc
(
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
:=
u
.
getTabler
(
id
)
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
}
//参数
//List(indexName string, data types.Message, primaryKey []byte, count, direction int32) (rows []*Row, err error)
indexName
,
err
:=
call
.
Argument
(
1
)
.
ToString
()
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
}
prefix
,
err
:=
call
.
Argument
(
2
)
.
ToString
()
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
}
primaryKey
,
err
:=
call
.
Argument
(
3
)
.
ToString
()
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
}
count
,
err
:=
call
.
Argument
(
4
)
.
ToInteger
()
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
}
direction
,
err
:=
call
.
Argument
(
5
)
.
ToInteger
()
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
}
bprefix
:=
[]
byte
(
prefix
)
if
prefix
==
""
{
bprefix
=
nil
}
bprimaryKey
:=
[]
byte
(
primaryKey
)
if
primaryKey
==
""
{
bprimaryKey
=
nil
}
rows
,
err
:=
tab
.
ListIndex
(
indexName
,
bprefix
,
bprimaryKey
,
int32
(
count
),
int32
(
direction
))
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
}
_
,
isjoin
:=
tab
.
(
*
table
.
JoinTable
)
querylist
:=
make
([]
interface
{},
len
(
rows
))
for
i
:=
0
;
i
<
len
(
rows
);
i
++
{
if
isjoin
{
joindata
,
ok
:=
rows
[
i
]
.
Data
.
(
*
table
.
JoinData
)
if
!
ok
{
return
errReturn
(
vm
,
errors
.
New
(
"jointable has no joindata"
))
}
leftdata
,
ok
:=
joindata
.
Left
.
(
*
jsproto
.
JsLog
)
if
!
ok
{
return
errReturn
(
vm
,
errors
.
New
(
"leftdata is not JsLog"
))
}
rightdata
,
ok
:=
joindata
.
Right
.
(
*
jsproto
.
JsLog
)
if
!
ok
{
return
errReturn
(
vm
,
errors
.
New
(
"rightdata is not jslog"
))
}
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
:=
make
(
map
[
string
]
interface
{})
obj
[
"left"
]
=
leftdata
.
Data
querylist
[
i
]
=
obj
}
}
retvalue
,
err
:=
vm
.
ToValue
(
querylist
)
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
}
return
retvalue
})
}
func
(
u
*
js
)
tableJoinFunc
(
vm
*
otto
.
Otto
)
{
vm
.
Set
(
"new_join_table"
,
func
(
call
otto
.
FunctionCall
)
otto
.
Value
{
vm
.
Set
(
"new_join_table"
,
func
(
call
otto
.
FunctionCall
)
otto
.
Value
{
left
,
err
:=
call
.
Argument
(
0
)
.
ToInteger
()
left
,
err
:=
call
.
Argument
(
0
)
.
ToInteger
()
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
lefttab
,
err
:=
getTable
(
left
)
lefttab
,
err
:=
u
.
getTable
(
left
)
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
...
@@ -253,7 +375,7 @@ func tableJoinFunc(vm *otto.Otto) {
...
@@ -253,7 +375,7 @@ func tableJoinFunc(vm *otto.Otto) {
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
righttab
,
err
:=
getTable
(
right
)
righttab
,
err
:=
u
.
getTable
(
right
)
if
err
!=
nil
{
if
err
!=
nil
{
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
...
@@ -266,18 +388,9 @@ func tableJoinFunc(vm *otto.Otto) {
...
@@ -266,18 +388,9 @@ func tableJoinFunc(vm *otto.Otto) {
return
errReturn
(
vm
,
err
)
return
errReturn
(
vm
,
err
)
}
}
var
id
int64
var
id
int64
for
{
u
.
globalHanldeID
++
id
=
atomic
.
AddInt64
(
&
globalHanldeID
,
1
)
%
maxjsint
id
=
u
.
globalHanldeID
if
_
,
ok
:=
globalTableHandle
.
Load
(
id
);
ok
{
u
.
globalTableHandle
.
Store
(
id
,
join
)
continue
}
if
id
<
0
{
atomic
.
StoreInt64
(
&
globalHanldeID
,
0
)
continue
}
break
}
globalTableHandle
.
Store
(
id
,
join
)
return
newObject
(
vm
)
.
setValue
(
"id"
,
id
)
.
value
()
return
newObject
(
vm
)
.
setValue
(
"id"
,
id
)
.
value
()
})
})
}
}
...
@@ -299,18 +412,25 @@ handle := new_join_table(left, right, listofjoinindex)
...
@@ -299,18 +412,25 @@ handle := new_join_table(left, right, listofjoinindex)
//JSONRow meta
//JSONRow meta
type
JSONRow
struct
{
type
JSONRow
struct
{
*
jsproto
.
JsLog
*
jsproto
.
JsLog
config
map
[
string
]
string
config
map
[
string
]
string
data
map
[
string
]
interface
{}
data
map
[
string
]
interface
{}
lastdata
types
.
Message
isint
*
regexp
.
Regexp
isfloat
*
regexp
.
Regexp
defaultvalue
string
}
}
//NewJSONRow 创建一个row
//NewJSONRow 创建一个row
func
NewJSONRow
(
config
string
,
defaultvalue
string
)
(
*
JSONRow
,
error
)
{
func
NewJSONRow
(
config
string
,
defaultvalue
string
)
(
*
JSONRow
,
error
)
{
row
:=
&
JSONRow
{}
row
:=
&
JSONRow
{}
row
.
isint
=
regexp
.
MustCompile
(
`%\d*d`
)
row
.
isfloat
=
regexp
.
MustCompile
(
`%[\.\d]*f`
)
row
.
config
=
make
(
map
[
string
]
string
)
row
.
config
=
make
(
map
[
string
]
string
)
err
:=
json
.
Unmarshal
([]
byte
(
config
),
row
.
config
)
err
:=
json
.
Unmarshal
([]
byte
(
config
),
&
row
.
config
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
row
.
defaultvalue
=
defaultvalue
row
.
JsLog
=
&
jsproto
.
JsLog
{
Data
:
defaultvalue
}
row
.
JsLog
=
&
jsproto
.
JsLog
{
Data
:
defaultvalue
}
err
=
row
.
parse
()
err
=
row
.
parse
()
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -321,16 +441,22 @@ func NewJSONRow(config string, defaultvalue string) (*JSONRow, error) {
...
@@ -321,16 +441,22 @@ func NewJSONRow(config string, defaultvalue string) (*JSONRow, error) {
//CreateRow 创建一行
//CreateRow 创建一行
func
(
row
*
JSONRow
)
CreateRow
()
*
table
.
Row
{
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
{
func
(
row
*
JSONRow
)
parse
()
error
{
row
.
data
=
make
(
map
[
string
]
interface
{})
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
()
return
d
.
Decode
(
&
row
.
data
)
}
}
//SetPayload 设置行的内容
//SetPayload 设置行的内容
func
(
row
*
JSONRow
)
SetPayload
(
data
types
.
Message
)
error
{
func
(
row
*
JSONRow
)
SetPayload
(
data
types
.
Message
)
error
{
if
row
.
lastdata
==
data
{
return
nil
}
row
.
lastdata
=
data
if
rowdata
,
ok
:=
data
.
(
*
jsproto
.
JsLog
);
ok
{
if
rowdata
,
ok
:=
data
.
(
*
jsproto
.
JsLog
);
ok
{
row
.
JsLog
=
rowdata
row
.
JsLog
=
rowdata
return
row
.
parse
()
return
row
.
parse
()
...
@@ -340,10 +466,34 @@ func (row *JSONRow) SetPayload(data types.Message) error {
...
@@ -340,10 +466,34 @@ func (row *JSONRow) SetPayload(data types.Message) error {
//Get value of row
//Get value of row
func
(
row
*
JSONRow
)
Get
(
key
string
)
([]
byte
,
error
)
{
func
(
row
*
JSONRow
)
Get
(
key
string
)
([]
byte
,
error
)
{
v
,
err
:=
row
.
get
(
key
)
return
v
,
err
}
func
(
row
*
JSONRow
)
get
(
key
string
)
([]
byte
,
error
)
{
if
format
,
ok
:=
row
.
config
[
key
];
ok
{
if
format
,
ok
:=
row
.
config
[
key
];
ok
{
if
data
,
ok
:=
row
.
data
[
key
];
ok
{
if
data
,
ok
:=
row
.
data
[
key
];
ok
{
if
row
.
isint
.
Match
([]
byte
(
format
))
{
//int
s
:=
fmt
.
Sprint
(
data
)
num
,
err
:=
strconv
.
ParseInt
(
s
,
10
,
64
)
if
err
!=
nil
{
return
nil
,
err
}
return
[]
byte
(
fmt
.
Sprintf
(
format
,
num
)),
nil
}
else
if
row
.
isfloat
.
Match
([]
byte
(
format
))
{
//float
s
:=
fmt
.
Sprint
(
data
)
num
,
err
:=
strconv
.
ParseFloat
(
s
,
64
)
if
err
!=
nil
{
return
nil
,
err
}
return
[]
byte
(
fmt
.
Sprintf
(
format
,
num
)),
nil
}
else
{
//string
if
n
,
ok
:=
data
.
(
json
.
Number
);
ok
{
data
=
n
.
String
()
}
}
return
[]
byte
(
fmt
.
Sprintf
(
format
,
data
)),
nil
return
[]
byte
(
fmt
.
Sprintf
(
format
,
data
)),
nil
}
}
}
}
return
nil
,
types
.
ErrNotFound
return
nil
,
errors
.
New
(
"get key "
+
key
+
"from data err"
)
}
}
plugin/dapp/js/executor/test.js
View file @
7b849e3c
//数据结构设计
//数据结构设计
//kvlist [{key:"key1", value:"value1"},{key:"key2", value:"value2"}]
//log 设计 {json data}
function
Init
(
context
)
{
function
Init
(
context
)
{
this
.
kvc
=
new
kvcreator
(
"init"
)
this
.
kvc
=
new
kvcreator
(
"init"
)
this
.
context
=
context
this
.
context
=
context
...
@@ -9,22 +7,6 @@ function Init(context) {
...
@@ -9,22 +7,6 @@ function Init(context) {
return
this
.
kvc
.
receipt
()
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
)
{
Exec
.
prototype
.
hello
=
function
(
args
)
{
this
.
kvc
.
add
(
"args"
,
args
)
this
.
kvc
.
add
(
"args"
,
args
)
this
.
kvc
.
add
(
"action"
,
"exec"
)
this
.
kvc
.
add
(
"action"
,
"exec"
)
...
...
plugin/dapp/js/plugin.go
View file @
7b849e3c
package
unfreeze
package
js
import
(
import
(
"github.com/33cn/chain33/pluginmgr"
"github.com/33cn/chain33/pluginmgr"
"github.com/33cn/plugin/plugin/dapp/js/cmd"
"github.com/33cn/plugin/plugin/dapp/js/executor"
"github.com/33cn/plugin/plugin/dapp/js/executor"
ptypes
"github.com/33cn/plugin/plugin/dapp/js/types"
ptypes
"github.com/33cn/plugin/plugin/dapp/js/types"
)
)
...
@@ -11,7 +12,7 @@ func init() {
...
@@ -11,7 +12,7 @@ func init() {
Name
:
ptypes
.
JsX
,
Name
:
ptypes
.
JsX
,
ExecName
:
executor
.
GetName
(),
ExecName
:
executor
.
GetName
(),
Exec
:
executor
.
Init
,
Exec
:
executor
.
Init
,
Cmd
:
nil
,
Cmd
:
cmd
.
JavaScriptCmd
,
RPC
:
nil
,
RPC
:
nil
,
})
})
}
}
vendor/github.com/33cn/chain33/build/while.sh
View file @
7b849e3c
...
@@ -2,4 +2,6 @@
...
@@ -2,4 +2,6 @@
while
:
;
do
while
:
;
do
./chain33-cli net
time
./chain33-cli net
time
#nc -vz localhost 8805
sleep
1
done
done
vendor/github.com/33cn/chain33/cmd/chain33/chain33.test.toml
View file @
7b849e3c
...
@@ -189,4 +189,9 @@ superManager=[
...
@@ -189,4 +189,9 @@ superManager=[
"1Bsg9j6gW83sShoee1fZAt9TkUjcrCgA9S"
,
"1Bsg9j6gW83sShoee1fZAt9TkUjcrCgA9S"
,
"12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv"
,
"12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv"
,
"1Q8hGLfoGe63efeWa8fJ4Pnukhkngt6poK"
"1Q8hGLfoGe63efeWa8fJ4Pnukhkngt6poK"
]
]
\ No newline at end of file
[health]
listenAddr
=
"localhost:8805"
checkInterval
=
1
unSyncMaxTimes
=
2
\ No newline at end of file
vendor/github.com/33cn/chain33/common/db/table/table.go
View file @
7b849e3c
...
@@ -312,6 +312,16 @@ func (table *Table) getPrimaryFromData(data types.Message) (primaryKey []byte, e
...
@@ -312,6 +312,16 @@ func (table *Table) getPrimaryFromData(data types.Message) (primaryKey []byte, e
return
return
}
}
//ListIndex list table index
func
(
table
*
Table
)
ListIndex
(
indexName
string
,
prefix
[]
byte
,
primaryKey
[]
byte
,
count
,
direction
int32
)
(
rows
[]
*
Row
,
err
error
)
{
kvdb
,
ok
:=
table
.
kvdb
.
(
db
.
KVDB
)
if
!
ok
{
return
nil
,
errors
.
New
(
"list only support KVDB interface"
)
}
query
:=
&
Query
{
table
:
table
,
kvdb
:
kvdb
}
return
query
.
ListIndex
(
indexName
,
prefix
,
primaryKey
,
count
,
direction
)
}
//Replace 如果有重复的,那么替换
//Replace 如果有重复的,那么替换
func
(
table
*
Table
)
Replace
(
data
types
.
Message
)
error
{
func
(
table
*
Table
)
Replace
(
data
types
.
Message
)
error
{
if
err
:=
table
.
checkIndex
(
data
);
err
!=
nil
{
if
err
:=
table
.
checkIndex
(
data
);
err
!=
nil
{
...
@@ -602,8 +612,15 @@ func (table *Table) getModify(row, oldrow *Row, index string) ([]byte, []byte, b
...
@@ -602,8 +612,15 @@ func (table *Table) getModify(row, oldrow *Row, index string) ([]byte, []byte, b
return
indexkey
,
oldkey
,
true
,
nil
return
indexkey
,
oldkey
,
true
,
nil
}
}
//GetQuery 获取查询结构
//GetQuery 获取查询结构
(允许传入 kvdb 为nil)
func
(
table
*
Table
)
GetQuery
(
kvdb
db
.
KVDB
)
*
Query
{
func
(
table
*
Table
)
GetQuery
(
kvdb
db
.
KVDB
)
*
Query
{
if
kvdb
==
nil
{
var
ok
bool
kvdb
,
ok
=
table
.
kvdb
.
(
db
.
KVDB
)
if
!
ok
{
return
nil
}
}
return
&
Query
{
table
:
table
,
kvdb
:
kvdb
}
return
&
Query
{
table
:
table
,
kvdb
:
kvdb
}
}
}
...
@@ -611,6 +628,11 @@ func (table *Table) getMeta() RowMeta {
...
@@ -611,6 +628,11 @@ func (table *Table) getMeta() RowMeta {
return
table
.
meta
return
table
.
meta
}
}
//GetMeta 获取meta
func
(
table
*
Table
)
GetMeta
()
RowMeta
{
return
table
.
getMeta
()
}
func
(
table
*
Table
)
getOpt
()
*
Option
{
func
(
table
*
Table
)
getOpt
()
*
Option
{
return
table
.
opt
return
table
.
opt
}
}
vendor/github.com/33cn/chain33/system/store/base.go
View file @
7b849e3c
...
@@ -90,64 +90,82 @@ func (store *BaseStore) Wait() {}
...
@@ -90,64 +90,82 @@ func (store *BaseStore) Wait() {}
func
(
store
*
BaseStore
)
processMessage
(
msg
queue
.
Message
)
{
func
(
store
*
BaseStore
)
processMessage
(
msg
queue
.
Message
)
{
client
:=
store
.
qclient
client
:=
store
.
qclient
if
msg
.
Ty
==
types
.
EventStoreSet
{
if
msg
.
Ty
==
types
.
EventStoreSet
{
datas
:=
msg
.
GetData
()
.
(
*
types
.
StoreSetWithSync
)
go
func
()
{
hash
,
err
:=
store
.
child
.
Set
(
datas
.
Storeset
,
datas
.
Sync
)
datas
:=
msg
.
GetData
()
.
(
*
types
.
StoreSetWithSync
)
if
err
!=
nil
{
hash
,
err
:=
store
.
child
.
Set
(
datas
.
Storeset
,
datas
.
Sync
)
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreSetReply
,
err
))
if
err
!=
nil
{
return
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreSetReply
,
err
))
}
return
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreSetReply
,
&
types
.
ReplyHash
{
Hash
:
hash
}))
}
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreSetReply
,
&
types
.
ReplyHash
{
Hash
:
hash
}))
}()
}
else
if
msg
.
Ty
==
types
.
EventStoreGet
{
}
else
if
msg
.
Ty
==
types
.
EventStoreGet
{
datas
:=
msg
.
GetData
()
.
(
*
types
.
StoreGet
)
go
func
()
{
values
:=
store
.
child
.
Get
(
datas
)
datas
:=
msg
.
GetData
()
.
(
*
types
.
StoreGet
)
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreGetReply
,
&
types
.
StoreReplyValue
{
Values
:
values
}))
values
:=
store
.
child
.
Get
(
datas
)
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreGetReply
,
&
types
.
StoreReplyValue
{
Values
:
values
}))
}()
}
else
if
msg
.
Ty
==
types
.
EventStoreMemSet
{
//只是在内存中set 一下,并不改变状态
}
else
if
msg
.
Ty
==
types
.
EventStoreMemSet
{
//只是在内存中set 一下,并不改变状态
datas
:=
msg
.
GetData
()
.
(
*
types
.
StoreSetWithSync
)
go
func
()
{
hash
,
err
:=
store
.
child
.
MemSet
(
datas
.
Storeset
,
datas
.
Sync
)
datas
:=
msg
.
GetData
()
.
(
*
types
.
StoreSetWithSync
)
if
err
!=
nil
{
hash
,
err
:=
store
.
child
.
MemSet
(
datas
.
Storeset
,
datas
.
Sync
)
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreSetReply
,
err
))
println
(
"EventStoreMemSet"
,
string
(
hash
))
return
if
err
!=
nil
{
}
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreSetReply
,
err
))
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreSetReply
,
&
types
.
ReplyHash
{
Hash
:
hash
}))
return
}
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreSetReply
,
&
types
.
ReplyHash
{
Hash
:
hash
}))
}()
}
else
if
msg
.
Ty
==
types
.
EventStoreCommit
{
//把内存中set 的交易 commit
}
else
if
msg
.
Ty
==
types
.
EventStoreCommit
{
//把内存中set 的交易 commit
req
:=
msg
.
GetData
()
.
(
*
types
.
ReqHash
)
go
func
()
{
hash
,
err
:=
store
.
child
.
Commit
(
req
)
req
:=
msg
.
GetData
()
.
(
*
types
.
ReqHash
)
if
hash
==
nil
{
println
(
"EventStoreCommit"
,
string
(
req
.
Hash
))
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreCommit
,
types
.
ErrHashNotFound
))
hash
,
err
:=
store
.
child
.
Commit
(
req
)
if
err
==
types
.
ErrDataBaseDamage
{
//如果是数据库写失败,需要上报给用户
if
hash
==
nil
{
go
util
.
ReportErrEventToFront
(
slog
,
client
,
"store"
,
"wallet"
,
err
)
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreCommit
,
types
.
ErrHashNotFound
))
if
err
==
types
.
ErrDataBaseDamage
{
//如果是数据库写失败,需要上报给用户
go
util
.
ReportErrEventToFront
(
slog
,
client
,
"store"
,
"wallet"
,
err
)
}
}
else
{
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreCommit
,
&
types
.
ReplyHash
{
Hash
:
hash
}))
}
}
}
else
{
}()
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreCommit
,
&
types
.
ReplyHash
{
Hash
:
hash
}))
}
}
else
if
msg
.
Ty
==
types
.
EventStoreRollback
{
}
else
if
msg
.
Ty
==
types
.
EventStoreRollback
{
req
:=
msg
.
GetData
()
.
(
*
types
.
ReqHash
)
go
func
()
{
hash
,
err
:=
store
.
child
.
Rollback
(
req
)
req
:=
msg
.
GetData
()
.
(
*
types
.
ReqHash
)
if
err
!=
nil
{
hash
,
err
:=
store
.
child
.
Rollback
(
req
)
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreRollback
,
types
.
ErrHashNotFound
))
if
err
!=
nil
{
}
else
{
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreRollback
,
types
.
ErrHashNotFound
))
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreRollback
,
&
types
.
ReplyHash
{
Hash
:
hash
}))
}
else
{
}
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreRollback
,
&
types
.
ReplyHash
{
Hash
:
hash
}))
}
}()
}
else
if
msg
.
Ty
==
types
.
EventStoreGetTotalCoins
{
}
else
if
msg
.
Ty
==
types
.
EventStoreGetTotalCoins
{
req
:=
msg
.
GetData
()
.
(
*
types
.
IterateRangeByStateHash
)
go
func
()
{
resp
:=
&
types
.
ReplyGetTotalCoins
{}
req
:=
msg
.
GetData
()
.
(
*
types
.
IterateRangeByStateHash
)
resp
.
Count
=
req
.
Count
resp
:=
&
types
.
ReplyGetTotalCoins
{}
store
.
child
.
IterateRangeByStateHash
(
req
.
StateHash
,
req
.
Start
,
req
.
End
,
true
,
resp
.
IterateRangeByStateHash
)
resp
.
Count
=
req
.
Count
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventGetTotalCoinsReply
,
resp
))
store
.
child
.
IterateRangeByStateHash
(
req
.
StateHash
,
req
.
Start
,
req
.
End
,
true
,
resp
.
IterateRangeByStateHash
)
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventGetTotalCoinsReply
,
resp
))
}()
}
else
if
msg
.
Ty
==
types
.
EventStoreDel
{
}
else
if
msg
.
Ty
==
types
.
EventStoreDel
{
req
:=
msg
.
GetData
()
.
(
*
types
.
StoreDel
)
go
func
()
{
hash
,
err
:=
store
.
child
.
Del
(
req
)
req
:=
msg
.
GetData
()
.
(
*
types
.
StoreDel
)
if
err
!=
nil
{
hash
,
err
:=
store
.
child
.
Del
(
req
)
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreDel
,
types
.
ErrHashNotFound
))
if
err
!=
nil
{
}
else
{
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreDel
,
types
.
ErrHashNotFound
))
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreDel
,
&
types
.
ReplyHash
{
Hash
:
hash
}))
}
else
{
}
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreDel
,
&
types
.
ReplyHash
{
Hash
:
hash
}))
}
}()
}
else
if
msg
.
Ty
==
types
.
EventStoreList
{
}
else
if
msg
.
Ty
==
types
.
EventStoreList
{
req
:=
msg
.
GetData
()
.
(
*
types
.
StoreList
)
go
func
()
{
query
:=
NewStoreListQuery
(
store
.
child
,
req
)
req
:=
msg
.
GetData
()
.
(
*
types
.
StoreList
)
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreListReply
,
query
.
Run
()))
query
:=
NewStoreListQuery
(
store
.
child
,
req
)
msg
.
Reply
(
client
.
NewMessage
(
""
,
types
.
EventStoreListReply
,
query
.
Run
()))
}()
}
else
{
}
else
{
store
.
child
.
ProcEvent
(
msg
)
go
store
.
child
.
ProcEvent
(
msg
)
}
}
}
}
...
...
vendor/github.com/33cn/chain33/system/store/mavl/db/tree.go
View file @
7b849e3c
...
@@ -45,9 +45,8 @@ func EnableMVCC(enable bool) {
...
@@ -45,9 +45,8 @@ func EnableMVCC(enable bool) {
// Tree merkle avl tree
// Tree merkle avl tree
type
Tree
struct
{
type
Tree
struct
{
root
*
Node
root
*
Node
ndb
*
nodeDB
ndb
*
nodeDB
//batch *nodeBatch
blockHeight
int64
blockHeight
int64
}
}
...
@@ -135,7 +134,9 @@ func (t *Tree) Save() []byte {
...
@@ -135,7 +134,9 @@ func (t *Tree) Save() []byte {
if
t
.
ndb
!=
nil
{
if
t
.
ndb
!=
nil
{
saveNodeNo
:=
t
.
root
.
save
(
t
)
saveNodeNo
:=
t
.
root
.
save
(
t
)
treelog
.
Debug
(
"Tree.Save"
,
"saveNodeNo"
,
saveNodeNo
,
"tree height"
,
t
.
blockHeight
)
treelog
.
Debug
(
"Tree.Save"
,
"saveNodeNo"
,
saveNodeNo
,
"tree height"
,
t
.
blockHeight
)
beg
:=
types
.
Now
()
err
:=
t
.
ndb
.
Commit
()
err
:=
t
.
ndb
.
Commit
()
treelog
.
Info
(
"tree.commit"
,
"cost"
,
types
.
Since
(
beg
))
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
return
nil
}
}
...
@@ -268,10 +269,6 @@ type nodeDB struct {
...
@@ -268,10 +269,6 @@ type nodeDB struct {
orphans
map
[
string
]
struct
{}
orphans
map
[
string
]
struct
{}
}
}
type
nodeBatch
struct
{
batch
dbm
.
Batch
}
func
newNodeDB
(
db
dbm
.
DB
,
sync
bool
)
*
nodeDB
{
func
newNodeDB
(
db
dbm
.
DB
,
sync
bool
)
*
nodeDB
{
ndb
:=
&
nodeDB
{
ndb
:=
&
nodeDB
{
cache
:
db
.
GetCache
(),
cache
:
db
.
GetCache
(),
...
@@ -312,11 +309,6 @@ func (ndb *nodeDB) GetNode(t *Tree, hash []byte) (*Node, error) {
...
@@ -312,11 +309,6 @@ func (ndb *nodeDB) GetNode(t *Tree, hash []byte) (*Node, error) {
return
node
,
nil
return
node
,
nil
}
}
// GetBatch get db batch handle
func
(
ndb
*
nodeDB
)
GetBatch
(
sync
bool
)
*
nodeBatch
{
return
&
nodeBatch
{
ndb
.
db
.
NewBatch
(
sync
)}
}
// 获取叶子节点的所有父节点
// 获取叶子节点的所有父节点
func
getHashNode
(
node
*
Node
)
(
hashs
[][]
byte
)
{
func
getHashNode
(
node
*
Node
)
(
hashs
[][]
byte
)
{
for
{
for
{
...
...
vendor/github.com/33cn/chain33/system/store/mavl/mavl.go
View file @
7b849e3c
...
@@ -6,6 +6,8 @@
...
@@ -6,6 +6,8 @@
package
mavl
package
mavl
import
(
import
(
"sync"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common"
clog
"github.com/33cn/chain33/common/log"
clog
"github.com/33cn/chain33/common/log"
log
"github.com/33cn/chain33/common/log/log15"
log
"github.com/33cn/chain33/common/log/log15"
...
@@ -13,7 +15,6 @@ import (
...
@@ -13,7 +15,6 @@ import (
drivers
"github.com/33cn/chain33/system/store"
drivers
"github.com/33cn/chain33/system/store"
mavl
"github.com/33cn/chain33/system/store/mavl/db"
mavl
"github.com/33cn/chain33/system/store/mavl/db"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/types"
lru
"github.com/hashicorp/golang-lru"
)
)
var
mlog
=
log
.
New
(
"module"
,
"mavl"
)
var
mlog
=
log
.
New
(
"module"
,
"mavl"
)
...
@@ -31,8 +32,7 @@ func DisableLog() {
...
@@ -31,8 +32,7 @@ func DisableLog() {
// Store mavl store struct
// Store mavl store struct
type
Store
struct
{
type
Store
struct
{
*
drivers
.
BaseStore
*
drivers
.
BaseStore
trees
map
[
string
]
*
mavl
.
Tree
trees
*
sync
.
Map
cache
*
lru
.
Cache
enableMavlPrefix
bool
enableMavlPrefix
bool
enableMVCC
bool
enableMVCC
bool
enableMavlPrune
bool
enableMavlPrune
bool
...
@@ -57,10 +57,7 @@ func New(cfg *types.Store, sub []byte) queue.Module {
...
@@ -57,10 +57,7 @@ func New(cfg *types.Store, sub []byte) queue.Module {
if
sub
!=
nil
{
if
sub
!=
nil
{
types
.
MustDecode
(
sub
,
&
subcfg
)
types
.
MustDecode
(
sub
,
&
subcfg
)
}
}
mavls
:=
&
Store
{
bs
,
make
(
map
[
string
]
*
mavl
.
Tree
),
nil
,
subcfg
.
EnableMavlPrefix
,
subcfg
.
EnableMVCC
,
subcfg
.
EnableMavlPrune
,
subcfg
.
PruneHeight
}
mavls
:=
&
Store
{
bs
,
&
sync
.
Map
{},
subcfg
.
EnableMavlPrefix
,
subcfg
.
EnableMVCC
,
subcfg
.
EnableMavlPrune
,
subcfg
.
PruneHeight
}
mavls
.
cache
,
_
=
lru
.
New
(
10
)
//使能前缀mavl以及MVCC
mavls
.
enableMavlPrefix
=
subcfg
.
EnableMavlPrefix
mavls
.
enableMavlPrefix
=
subcfg
.
EnableMavlPrefix
mavls
.
enableMVCC
=
subcfg
.
EnableMVCC
mavls
.
enableMVCC
=
subcfg
.
EnableMVCC
mavls
.
enableMavlPrune
=
subcfg
.
EnableMavlPrune
mavls
.
enableMavlPrune
=
subcfg
.
EnableMavlPrune
...
@@ -91,18 +88,13 @@ func (mavls *Store) Get(datas *types.StoreGet) [][]byte {
...
@@ -91,18 +88,13 @@ func (mavls *Store) Get(datas *types.StoreGet) [][]byte {
var
err
error
var
err
error
values
:=
make
([][]
byte
,
len
(
datas
.
Keys
))
values
:=
make
([][]
byte
,
len
(
datas
.
Keys
))
search
:=
string
(
datas
.
StateHash
)
search
:=
string
(
datas
.
StateHash
)
if
data
,
ok
:=
mavls
.
cache
.
Get
(
search
);
ok
{
if
data
,
ok
:=
mavls
.
trees
.
Load
(
search
);
ok
{
tree
=
data
.
(
*
mavl
.
Tree
)
tree
=
data
.
(
*
mavl
.
Tree
)
}
else
if
data
,
ok
:=
mavls
.
trees
[
search
];
ok
{
tree
=
data
}
else
{
}
else
{
tree
=
mavl
.
NewTree
(
mavls
.
GetDB
(),
true
)
tree
=
mavl
.
NewTree
(
mavls
.
GetDB
(),
true
)
//get接口也应该传入高度
//get接口也应该传入高度
//tree.SetBlockHeight(datas.Height)
//tree.SetBlockHeight(datas.Height)
err
=
tree
.
Load
(
datas
.
StateHash
)
err
=
tree
.
Load
(
datas
.
StateHash
)
if
err
==
nil
{
mavls
.
cache
.
Add
(
search
,
tree
)
}
mlog
.
Debug
(
"store mavl get tree"
,
"err"
,
err
,
"StateHash"
,
common
.
ToHex
(
datas
.
StateHash
))
mlog
.
Debug
(
"store mavl get tree"
,
"err"
,
err
,
"StateHash"
,
common
.
ToHex
(
datas
.
StateHash
))
}
}
if
err
==
nil
{
if
err
==
nil
{
...
@@ -118,9 +110,13 @@ func (mavls *Store) Get(datas *types.StoreGet) [][]byte {
...
@@ -118,9 +110,13 @@ func (mavls *Store) Get(datas *types.StoreGet) [][]byte {
// MemSet set keys values to memcory mavl, return root hash and error
// MemSet set keys values to memcory mavl, return root hash and error
func
(
mavls
*
Store
)
MemSet
(
datas
*
types
.
StoreSet
,
sync
bool
)
([]
byte
,
error
)
{
func
(
mavls
*
Store
)
MemSet
(
datas
*
types
.
StoreSet
,
sync
bool
)
([]
byte
,
error
)
{
beg
:=
types
.
Now
()
defer
func
()
{
mlog
.
Info
(
"MemSet"
,
"cost"
,
types
.
Since
(
beg
))
}()
if
len
(
datas
.
KV
)
==
0
{
if
len
(
datas
.
KV
)
==
0
{
mlog
.
Info
(
"store mavl memset,use preStateHash as stateHash for kvset is null"
)
mlog
.
Info
(
"store mavl memset,use preStateHash as stateHash for kvset is null"
)
mavls
.
trees
[
string
(
datas
.
StateHash
)]
=
nil
mavls
.
trees
.
Store
(
string
(
datas
.
StateHash
),
nil
)
return
datas
.
StateHash
,
nil
return
datas
.
StateHash
,
nil
}
}
tree
:=
mavl
.
NewTree
(
mavls
.
GetDB
(),
sync
)
tree
:=
mavl
.
NewTree
(
mavls
.
GetDB
(),
sync
)
...
@@ -133,44 +129,47 @@ func (mavls *Store) MemSet(datas *types.StoreSet, sync bool) ([]byte, error) {
...
@@ -133,44 +129,47 @@ func (mavls *Store) MemSet(datas *types.StoreSet, sync bool) ([]byte, error) {
tree
.
Set
(
datas
.
KV
[
i
]
.
Key
,
datas
.
KV
[
i
]
.
Value
)
tree
.
Set
(
datas
.
KV
[
i
]
.
Key
,
datas
.
KV
[
i
]
.
Value
)
}
}
hash
:=
tree
.
Hash
()
hash
:=
tree
.
Hash
()
mavls
.
trees
[
string
(
hash
)]
=
tree
mavls
.
trees
.
Store
(
string
(
hash
),
tree
)
if
len
(
mavls
.
trees
)
>
1000
{
mlog
.
Error
(
"too many trees in cache"
)
}
return
hash
,
nil
return
hash
,
nil
}
}
// Commit convert memcory mavl to storage db
// Commit convert memcory mavl to storage db
func
(
mavls
*
Store
)
Commit
(
req
*
types
.
ReqHash
)
([]
byte
,
error
)
{
func
(
mavls
*
Store
)
Commit
(
req
*
types
.
ReqHash
)
([]
byte
,
error
)
{
tree
,
ok
:=
mavls
.
trees
[
string
(
req
.
Hash
)]
beg
:=
types
.
Now
()
defer
func
()
{
mlog
.
Info
(
"Commit"
,
"cost"
,
types
.
Since
(
beg
))
}()
tree
,
ok
:=
mavls
.
trees
.
Load
(
string
(
req
.
Hash
))
if
!
ok
{
if
!
ok
{
mlog
.
Error
(
"store mavl commit"
,
"err"
,
types
.
ErrHashNotFound
)
mlog
.
Error
(
"store mavl commit"
,
"err"
,
types
.
ErrHashNotFound
)
return
nil
,
types
.
ErrHashNotFound
return
nil
,
types
.
ErrHashNotFound
}
}
if
tree
==
nil
{
if
tree
==
nil
{
mlog
.
Info
(
"store mavl commit,do nothing for kvset is null"
)
mlog
.
Info
(
"store mavl commit,do nothing for kvset is null"
)
delete
(
mavls
.
trees
,
string
(
req
.
Hash
))
mavls
.
trees
.
Delete
(
string
(
req
.
Hash
))
return
req
.
Hash
,
nil
return
req
.
Hash
,
nil
}
}
hash
:=
tree
.
(
*
mavl
.
Tree
)
.
Save
()
hash
:=
tree
.
Save
()
if
hash
==
nil
{
if
hash
==
nil
{
mlog
.
Error
(
"store mavl commit"
,
"err"
,
types
.
ErrHashNotFound
)
mlog
.
Error
(
"store mavl commit"
,
"err"
,
types
.
ErrHashNotFound
)
return
nil
,
types
.
ErrDataBaseDamage
return
nil
,
types
.
ErrDataBaseDamage
}
}
delete
(
mavls
.
trees
,
string
(
req
.
Hash
))
mavls
.
trees
.
Delete
(
string
(
req
.
Hash
))
return
req
.
Hash
,
nil
return
req
.
Hash
,
nil
}
}
// Rollback 回退将缓存的mavl树删除掉
// Rollback 回退将缓存的mavl树删除掉
func
(
mavls
*
Store
)
Rollback
(
req
*
types
.
ReqHash
)
([]
byte
,
error
)
{
func
(
mavls
*
Store
)
Rollback
(
req
*
types
.
ReqHash
)
([]
byte
,
error
)
{
_
,
ok
:=
mavls
.
trees
[
string
(
req
.
Hash
)]
beg
:=
types
.
Now
()
defer
func
()
{
mlog
.
Info
(
"Rollback"
,
"cost"
,
types
.
Since
(
beg
))
}()
_
,
ok
:=
mavls
.
trees
.
Load
(
string
(
req
.
Hash
))
if
!
ok
{
if
!
ok
{
mlog
.
Error
(
"store mavl rollback"
,
"err"
,
types
.
ErrHashNotFound
)
mlog
.
Error
(
"store mavl rollback"
,
"err"
,
types
.
ErrHashNotFound
)
return
nil
,
types
.
ErrHashNotFound
return
nil
,
types
.
ErrHashNotFound
}
}
delete
(
mavls
.
trees
,
string
(
req
.
Hash
))
mavls
.
trees
.
Delete
(
string
(
req
.
Hash
))
return
req
.
Hash
,
nil
return
req
.
Hash
,
nil
}
}
...
...
vendor/github.com/33cn/chain33/types/cfg.go
View file @
7b849e3c
...
@@ -6,21 +6,22 @@ package types
...
@@ -6,21 +6,22 @@ package types
// Config 配置信息
// Config 配置信息
type
Config
struct
{
type
Config
struct
{
Title
string
`protobuf:"bytes,1,opt,name=title" json:"title,omitempty"`
Title
string
`protobuf:"bytes,1,opt,name=title" json:"title,omitempty"`
Version
string
`protobuf:"bytes,1,opt,name=version" json:"version,omitempty"`
Version
string
`protobuf:"bytes,1,opt,name=version" json:"version,omitempty"`
Log
*
Log
`protobuf:"bytes,2,opt,name=log" json:"log,omitempty"`
Log
*
Log
`protobuf:"bytes,2,opt,name=log" json:"log,omitempty"`
Store
*
Store
`protobuf:"bytes,3,opt,name=store" json:"store,omitempty"`
Store
*
Store
`protobuf:"bytes,3,opt,name=store" json:"store,omitempty"`
Consensus
*
Consensus
`protobuf:"bytes,5,opt,name=consensus" json:"consensus,omitempty"`
Consensus
*
Consensus
`protobuf:"bytes,5,opt,name=consensus" json:"consensus,omitempty"`
Mempool
*
Mempool
`protobuf:"bytes,6,opt,name=mempool" json:"memPool,omitempty"`
Mempool
*
Mempool
`protobuf:"bytes,6,opt,name=mempool" json:"memPool,omitempty"`
BlockChain
*
BlockChain
`protobuf:"bytes,7,opt,name=blockChain" json:"blockChain,omitempty"`
BlockChain
*
BlockChain
`protobuf:"bytes,7,opt,name=blockChain" json:"blockChain,omitempty"`
Wallet
*
Wallet
`protobuf:"bytes,8,opt,name=wallet" json:"wallet,omitempty"`
Wallet
*
Wallet
`protobuf:"bytes,8,opt,name=wallet" json:"wallet,omitempty"`
P2P
*
P2P
`protobuf:"bytes,9,opt,name=p2p" json:"p2p,omitempty"`
P2P
*
P2P
`protobuf:"bytes,9,opt,name=p2p" json:"p2p,omitempty"`
RPC
*
RPC
`protobuf:"bytes,10,opt,name=rpc" json:"rpc,omitempty"`
RPC
*
RPC
`protobuf:"bytes,10,opt,name=rpc" json:"rpc,omitempty"`
Exec
*
Exec
`protobuf:"bytes,11,opt,name=exec" json:"exec,omitempty"`
Exec
*
Exec
`protobuf:"bytes,11,opt,name=exec" json:"exec,omitempty"`
TestNet
bool
`protobuf:"varint,12,opt,name=testNet" json:"testNet,omitempty"`
TestNet
bool
`protobuf:"varint,12,opt,name=testNet" json:"testNet,omitempty"`
FixTime
bool
`protobuf:"varint,13,opt,name=fixTime" json:"fixTime,omitempty"`
FixTime
bool
`protobuf:"varint,13,opt,name=fixTime" json:"fixTime,omitempty"`
Pprof
*
Pprof
`protobuf:"bytes,14,opt,name=pprof" json:"pprof,omitempty"`
Pprof
*
Pprof
`protobuf:"bytes,14,opt,name=pprof" json:"pprof,omitempty"`
Fork
*
ForkList
`protobuf:"bytes,15,opt,name=fork" json:"fork,omitempty"`
Fork
*
ForkList
`protobuf:"bytes,15,opt,name=fork" json:"fork,omitempty"`
Health
*
HealthCheck
`protobuf:"bytes,16,opt,name=health" json:"health,omitempty"`
}
}
// ForkList fork列表配置
// ForkList fork列表配置
...
@@ -165,3 +166,10 @@ type Exec struct {
...
@@ -165,3 +166,10 @@ type Exec struct {
type
Pprof
struct
{
type
Pprof
struct
{
ListenAddr
string
`protobuf:"bytes,1,opt,name=listenAddr" json:"listenAddr,omitempty"`
ListenAddr
string
`protobuf:"bytes,1,opt,name=listenAddr" json:"listenAddr,omitempty"`
}
}
// HealthCheck 配置
type
HealthCheck
struct
{
ListenAddr
string
`protobuf:"bytes,1,opt,name=listenAddr" json:"listenAddr,omitempty"`
CheckInterval
uint32
`protobuf:"varint,2,opt,name=checkInterval" json:"checkInterval,omitempty"`
UnSyncMaxTimes
uint32
`protobuf:"varint,3,opt,name=unSyncMaxTimes" json:"unSyncMaxTimes,omitempty"`
}
vendor/github.com/33cn/chain33/util/cli/chain33.go
View file @
7b849e3c
...
@@ -171,6 +171,9 @@ func RunChain33(name string) {
...
@@ -171,6 +171,9 @@ func RunChain33(name string) {
log
.
Info
(
"loading wallet module"
)
log
.
Info
(
"loading wallet module"
)
walletm
:=
wallet
.
New
(
cfg
.
Wallet
,
sub
.
Wallet
)
walletm
:=
wallet
.
New
(
cfg
.
Wallet
,
sub
.
Wallet
)
walletm
.
SetQueueClient
(
q
.
Client
())
walletm
.
SetQueueClient
(
q
.
Client
())
health
:=
util
.
NewHealthCheckServer
(
q
.
Client
())
health
.
Start
(
cfg
.
Health
)
defer
func
()
{
defer
func
()
{
//close all module,clean some resource
//close all module,clean some resource
log
.
Info
(
"begin close blockchain module"
)
log
.
Info
(
"begin close blockchain module"
)
...
@@ -189,6 +192,8 @@ func RunChain33(name string) {
...
@@ -189,6 +192,8 @@ func RunChain33(name string) {
rpcapi
.
Close
()
rpcapi
.
Close
()
log
.
Info
(
"begin close wallet module"
)
log
.
Info
(
"begin close wallet module"
)
walletm
.
Close
()
walletm
.
Close
()
log
.
Info
(
"begin close health module"
)
health
.
Close
()
log
.
Info
(
"begin close queue module"
)
log
.
Info
(
"begin close queue module"
)
q
.
Close
()
q
.
Close
()
...
...
vendor/github.com/33cn/chain33/util/healthcheck.go
0 → 100644
View file @
7b849e3c
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package
util
import
(
"net"
"time"
"sync"
"github.com/33cn/chain33/client"
log
"github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/queue"
"github.com/33cn/chain33/types"
)
var
(
listenAddr
=
"localhost:8805"
unSyncMaxTimes
uint32
=
6
//max 6 times
checkInterval
uint32
=
5
// 5s
)
// HealthCheckServer a node's health check server
type
HealthCheckServer
struct
{
api
client
.
QueueProtocolAPI
l
net
.
Listener
quit
chan
struct
{}
wg
sync
.
WaitGroup
}
// Close NewHealthCheckServer close
func
(
s
*
HealthCheckServer
)
Close
()
{
close
(
s
.
quit
)
s
.
wg
.
Wait
()
log
.
Info
(
"healthCheck quit"
)
}
// NewHealthCheckServer new json rpcserver object
func
NewHealthCheckServer
(
c
queue
.
Client
)
*
HealthCheckServer
{
h
:=
&
HealthCheckServer
{}
h
.
api
,
_
=
client
.
New
(
c
,
nil
)
h
.
quit
=
make
(
chan
struct
{})
return
h
}
// Start HealthCheckServer start
func
(
s
*
HealthCheckServer
)
Start
(
cfg
*
types
.
HealthCheck
)
{
if
cfg
!=
nil
{
if
cfg
.
ListenAddr
!=
""
{
listenAddr
=
cfg
.
ListenAddr
}
if
cfg
.
CheckInterval
!=
0
{
checkInterval
=
cfg
.
CheckInterval
}
if
cfg
.
UnSyncMaxTimes
!=
0
{
unSyncMaxTimes
=
cfg
.
UnSyncMaxTimes
}
}
log
.
Info
(
"healthCheck start "
,
"addr"
,
listenAddr
,
"inter"
,
checkInterval
,
"times"
,
unSyncMaxTimes
)
s
.
wg
.
Add
(
1
)
go
s
.
healthCheck
()
}
func
(
s
*
HealthCheckServer
)
listen
(
on
bool
)
error
{
if
on
{
listener
,
err
:=
net
.
Listen
(
"tcp"
,
listenAddr
)
if
err
!=
nil
{
return
err
}
s
.
l
=
listener
log
.
Info
(
"healthCheck listen open"
)
return
nil
}
if
s
.
l
!=
nil
{
err
:=
s
.
l
.
Close
()
if
err
!=
nil
{
return
err
}
log
.
Info
(
"healthCheck listen close"
)
s
.
l
=
nil
}
return
nil
}
func
(
s
*
HealthCheckServer
)
getHealth
(
sync
bool
)
(
bool
,
error
)
{
reply
,
err
:=
s
.
api
.
IsSync
()
if
err
!=
nil
{
return
false
,
err
}
peerList
,
err
:=
s
.
api
.
PeerInfo
()
if
err
!=
nil
{
return
false
,
err
}
log
.
Info
(
"healthCheck tick"
,
"peers"
,
len
(
peerList
.
Peers
),
"isSync"
,
reply
.
IsOk
,
"sync"
,
sync
)
return
len
(
peerList
.
Peers
)
>
1
&&
reply
.
IsOk
,
nil
}
func
(
s
*
HealthCheckServer
)
healthCheck
()
{
ticker
:=
time
.
NewTicker
(
time
.
Second
*
time
.
Duration
(
checkInterval
))
defer
ticker
.
Stop
()
defer
s
.
wg
.
Done
()
var
sync
bool
var
unSyncTimes
uint32
for
{
select
{
case
<-
s
.
quit
:
if
s
.
l
!=
nil
{
s
.
l
.
Close
()
}
if
s
.
api
!=
nil
{
s
.
api
.
Close
()
}
return
case
<-
ticker
.
C
:
health
,
err
:=
s
.
getHealth
(
sync
)
if
err
!=
nil
{
continue
}
//sync
if
health
{
if
!
sync
{
err
=
s
.
listen
(
true
)
if
err
!=
nil
{
log
.
Error
(
"healthCheck "
,
"listen open err"
,
err
.
Error
())
continue
}
sync
=
true
}
unSyncTimes
=
0
}
else
{
if
sync
{
if
unSyncTimes
>=
unSyncMaxTimes
{
err
=
s
.
listen
(
false
)
if
err
!=
nil
{
log
.
Error
(
"healthCheck "
,
"listen close err"
,
err
.
Error
())
continue
}
sync
=
false
}
unSyncTimes
++
}
}
}
}
}
vendor/github.com/33cn/chain33/util/healthcheck_test.go
0 → 100644
View file @
7b849e3c
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package
util
import
(
"testing"
"time"
"github.com/33cn/chain33/client/mocks"
"github.com/33cn/chain33/queue"
"github.com/33cn/chain33/types"
"github.com/stretchr/testify/assert"
)
func
TestStart
(
t
*
testing
.
T
)
{
q
:=
queue
.
New
(
"channel"
)
health
:=
NewHealthCheckServer
(
q
.
Client
())
api
:=
new
(
mocks
.
QueueProtocolAPI
)
reply
:=
&
types
.
Reply
{
IsOk
:
true
}
api
.
On
(
"IsSync"
)
.
Return
(
reply
,
nil
)
peer1
:=
&
types
.
Peer
{
Addr
:
"addr1"
}
peer2
:=
&
types
.
Peer
{
Addr
:
"addr2"
}
peers
:=
&
types
.
PeerList
{
Peers
:
[]
*
types
.
Peer
{
peer1
,
peer2
}}
api
.
On
(
"PeerInfo"
)
.
Return
(
peers
,
nil
)
api
.
On
(
"Close"
)
.
Return
()
health
.
api
=
api
cfg
,
_
:=
types
.
InitCfg
(
"../cmd/chain33/chain33.test.toml"
)
health
.
Start
(
cfg
.
Health
)
time
.
Sleep
(
time
.
Second
*
3
)
health
.
Close
()
time
.
Sleep
(
time
.
Second
*
1
)
}
func
TestGetHealth
(
t
*
testing
.
T
)
{
api
:=
new
(
mocks
.
QueueProtocolAPI
)
reply
:=
&
types
.
Reply
{
IsOk
:
true
}
api
.
On
(
"IsSync"
)
.
Return
(
reply
,
nil
)
.
Once
()
peer2
:=
&
types
.
Peer
{
Addr
:
"addr2"
}
peerlist
:=
&
types
.
PeerList
{
Peers
:
[]
*
types
.
Peer
{
peer2
}}
api
.
On
(
"PeerInfo"
)
.
Return
(
peerlist
,
nil
)
.
Once
()
q
:=
queue
.
New
(
"channel"
)
health
:=
NewHealthCheckServer
(
q
.
Client
())
health
.
api
=
api
ret
,
err
:=
health
.
getHealth
(
true
)
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
false
,
ret
)
}
vendor/github.com/33cn/chain33/util/testnode/testnode.go
View file @
7b849e3c
...
@@ -205,6 +205,27 @@ func (mock *Chain33Mock) SendAndSign(priv crypto.PrivKey, hextx string) ([]byte,
...
@@ -205,6 +205,27 @@ func (mock *Chain33Mock) SendAndSign(priv crypto.PrivKey, hextx string) ([]byte,
return
reply
.
GetMsg
(),
nil
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
)
{
func
newWalletRealize
(
qAPI
client
.
QueueProtocolAPI
)
{
seed
:=
&
types
.
SaveSeedByPw
{
seed
:=
&
types
.
SaveSeedByPw
{
Seed
:
"subject hamster apple parent vital can adult chapter fork business humor pen tiger void elephant"
,
Seed
:
"subject hamster apple parent vital can adult chapter fork business humor pen tiger void elephant"
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment