Commit 623207aa authored by 袁兴强's avatar 袁兴强

update wasm with chain33 plugin framework

parent 5c8468ee
......@@ -9,10 +9,7 @@ import (
//stateDB wrapper
func setStateDB(key, value []byte) {
wasmCB.kvs = append(wasmCB.kvs, &types.KeyValue{
Key: wasmCB.formatStateKey(key),
Value: value,
})
wasmCB.stateKVC.Add(key, value)
}
func getStateDBSize(key []byte) int {
......@@ -24,19 +21,14 @@ func getStateDBSize(key []byte) int {
}
func getStateDB(key []byte) ([]byte, error) {
return wasmCB.GetStateDB().Get(wasmCB.formatStateKey(key))
return wasmCB.stateKVC.Get(key)
}
//localDB wrapper
func setLocalDB(key, value []byte) {
preValue, _ := getLocalDB(key)
wasmCB.receiptLogs = append(wasmCB.receiptLogs, &types.ReceiptLog{
Ty: types2.TyLogLocalData,
Log: types.Encode(&types2.LocalDataLog{
Key: wasmCB.formatLocalKey(key),
PreValue: preValue,
CurValue: value,
}),
wasmCB.localCache = append(wasmCB.localCache, &types2.LocalDataLog{
Key: append(calcLocalPrefix(wasmCB.contractName), key...),
Value: value,
})
}
......@@ -49,7 +41,14 @@ func getLocalDBSize(key []byte) int {
}
func getLocalDB(key []byte) ([]byte, error) {
return wasmCB.GetLocalDB().Get(wasmCB.formatLocalKey(key))
newKey := append(calcLocalPrefix(wasmCB.contractName), key...)
// 先查缓存,再查数据库
for _, kv := range wasmCB.localCache {
if string(newKey) == string(kv.Key) {
return kv.Value, nil
}
}
return wasmCB.GetLocalDB().Get(newKey)
}
//account wrapper
......@@ -94,6 +93,7 @@ func transferWithdraw(addr, execaddr string, amount int64) error {
func execFrozen(addr string, amount int64) error {
receipt, err := wasmCB.GetCoinsAccount().ExecFrozen(addr, wasmCB.execAddr, amount)
if err != nil {
log.Error("execFrozen", "error", err)
return err
}
wasmCB.kvs = append(wasmCB.kvs, receipt.KV...)
......@@ -164,7 +164,7 @@ func getRandom() int64 {
}
func printlog(s string) {
wasmCB.logs = append(wasmCB.logs, s)
wasmCB.customLogs = append(wasmCB.customLogs, s)
}
func sha256(data []byte) []byte {
......
package executor
import (
"fmt"
"github.com/33cn/chain33/common/address"
)
const (
KeyPrefixContract = "mavl-wasm-%s:%s"
KeyPrefixLocal = "LODB-wasm-%s:%s"
"github.com/33cn/chain33/types"
types2 "github.com/33cn/plugin/plugin/dapp/wasm/types"
)
// "mavl-wasm-code-{name}"
func contractKey(name string) []byte {
contractAddr := address.ExecAddress(name)
key := "mavl-wasm-address:" + contractAddr
return []byte(key)
return append([]byte("mavl-"+types2.WasmX+"-code-"), []byte(name)...)
}
func (w *Wasm) formatStateKey(key []byte) []byte {
addr := address.ExecAddress(w.contractAddr)
return []byte(fmt.Sprintf(KeyPrefixContract, addr, string(key)))
// "mavl-wasm-{contract}-"
func calcStatePrefix(contract string) []byte {
var prefix []byte
prefix = append(prefix, types.CalcStatePrefix([]byte(types2.WasmX))...)
prefix = append(prefix, []byte(contract)...)
prefix = append(prefix, '-')
return prefix
}
func (w *Wasm) formatLocalKey(key []byte) []byte {
addr := address.ExecAddress(w.contractAddr)
return []byte(fmt.Sprintf(KeyPrefixLocal, addr, string(key)))
// "LODB-wasm-{contract}-"
func calcLocalPrefix(contract string) []byte {
var prefix []byte
prefix = append(prefix, types.CalcLocalPrefix([]byte(types2.WasmX))...)
prefix = append(prefix, []byte(contract)...)
prefix = append(prefix, '-')
return prefix
}
func (w *Wasm) contractExist(name string) bool {
_, err := w.GetStateDB().Get(contractKey(name))
if err != nil && err != types.ErrNotFound {
panic(err)
}
return err == nil
}
func (w *Wasm) getContract(name string) ([]byte, error) {
return w.GetStateDB().Get(contractKey(name))
}
......@@ -4,6 +4,7 @@ import (
"encoding/hex"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
types2 "github.com/33cn/plugin/plugin/dapp/wasm/types"
"github.com/perlin-network/life/compiler"
......@@ -13,30 +14,49 @@ import (
var wasmCB *Wasm
func (w *Wasm) userExecName(name string, local bool) string {
execer := "user." + types2.WasmX + "." + name
if local {
cfg := w.GetAPI().GetConfig()
execer = cfg.ExecName(execer)
}
return execer
}
func (w *Wasm) checkTxExec(txExec string, execName string) bool {
cfg := w.GetAPI().GetConfig()
return txExec == cfg.ExecName(execName)
}
func (w *Wasm) Exec_Create(payload *types2.WasmCreate, tx *types.Transaction, index int) (*types.Receipt, error) {
if payload == nil {
return nil, types.ErrInvalidParam
}
if !w.checkTxExec(string(tx.Execer), types2.WasmX) {
return nil, types.ErrExecNameNotMatch
}
name := payload.Name
if !validateName(name) {
return nil, types2.ErrInvalidContractName
}
if w.contractExist(name) {
return nil, types2.ErrContractExist
}
code := payload.Code
if len(code) > 1<<20 { //TODO: max size to define
if len(code) > types2.MaxCodeSize {
return nil, types2.ErrCodeOversize
}
if err := validation.ValidateWasm(code); err != nil {
return nil, types2.ErrInvalidWasm
}
var receiptLogs []*types.ReceiptLog
kv := []*types.KeyValue{{
Key: contractKey(name),
Value: code,
}}
kvc := dapp.NewKVCreator(w.GetStateDB(), nil, nil)
_, err := kvc.GetNoPrefix(contractKey(name))
if err == nil {
return nil, types2.ErrContractExist
}
if err != types.ErrNotFound {
return nil, err
}
kvc.AddNoPrefix(contractKey(name), code)
receiptLog := &types.ReceiptLog{
Ty: types2.TyLogWasmCreate,
......@@ -45,20 +65,25 @@ func (w *Wasm) Exec_Create(payload *types2.WasmCreate, tx *types.Transaction, in
Code: hex.EncodeToString(code),
}),
}
receiptLogs = append(receiptLogs, receiptLog)
return &types.Receipt{
Ty: types.ExecOk,
KV: kv,
Logs: receiptLogs,
KV: kvc.KVList(),
Logs: []*types.ReceiptLog{receiptLog},
}, nil
}
func (w *Wasm) Exec_Call(payload *types2.WasmCall, tx *types.Transaction, index int) (*types.Receipt, error) {
log.Info("into wasm Exec_Call...")
if payload == nil {
return nil, types.ErrInvalidParam
}
code, err := w.getContract(payload.Contract)
if !w.checkTxExec(string(tx.Execer), types2.WasmX) {
return nil, types.ErrExecNameNotMatch
}
w.stateKVC = dapp.NewKVCreator(w.GetStateDB(), calcStatePrefix(payload.Contract), nil)
code, err := w.stateKVC.GetNoPrefix(contractKey(payload.Contract))
if err != nil {
return nil, err
}
......@@ -78,9 +103,9 @@ func (w *Wasm) Exec_Call(payload *types2.WasmCall, tx *types.Transaction, index
return nil, types2.ErrInvalidMethod
}
w.contractAddr = address.ExecAddress(payload.Contract)
w.contractName = payload.Contract
w.tx = tx
w.execAddr = address.ExecAddress(string(tx.Execer))
w.execAddr = address.ExecAddress(string(types.GetRealExecName(tx.Execer)))
wasmCB = w
defer func() {
wasmCB = nil
......@@ -90,22 +115,31 @@ func (w *Wasm) Exec_Call(payload *types2.WasmCall, tx *types.Transaction, index
if err != nil {
return nil, err
}
var kvs []*types.KeyValue
kvs = append(kvs, w.kvs...)
kvs = append(kvs, w.stateKVC.KVList()...)
var logs []*types.ReceiptLog
logs = append(logs, &types.ReceiptLog{Ty: types2.TyLogWasmCall, Log: types.Encode(&types2.CallContractLog{
Contract: payload.Contract,
Method: payload.Method,
Result: ret,
})})
logs = append(logs, w.receiptLogs...)
logs = append(logs, &types.ReceiptLog{Ty: types2.TyLogCustom, Log: types.Encode(&types2.CustomLog{
Info: w.logs,
Info: w.customLogs,
})})
logs = append(logs, w.receiptLogs...)
for _, log := range w.localCache {
logs = append(logs, &types.ReceiptLog{
Ty: types2.TyLogLocalData,
Log: types.Encode(log),
})
}
receipt := &types.Receipt{
Ty: types.ExecOk,
KV: w.kvs,
KV: kvs,
Logs: logs,
}
if ret < 0 {
......
......@@ -6,28 +6,15 @@ import (
)
func (w *Wasm) ExecDelLocal_Create(payload *types2.WasmCreate, tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return execDelLocal(receipt)
return &types.LocalDBSet{}, nil
}
func (w *Wasm) ExecDelLocal_Call(payload *types2.WasmCall, tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return execDelLocal(receipt)
}
func execDelLocal(receipt *types.ReceiptData) (*types.LocalDBSet, error) {
if receipt.Ty != types.ExecOk {
return nil, nil
}
set := &types.LocalDBSet{}
for _, item := range receipt.Logs {
if item.Ty == types2.TyLogLocalData {
var data types2.LocalDataLog
err := types.Decode(item.Log, &data)
localExecer := w.userExecName(payload.Contract, true)
kvs, err := w.DelRollbackKV(tx, []byte(localExecer))
if err != nil {
log.Error("execLocal", "decode error", err)
continue
return nil, err
}
set.KV = append(set.KV, &types.KeyValue{Key: data.Key, Value: data.PreValue})
}
}
return set, nil
return &types.LocalDBSet{KV: kvs}, nil
}
......@@ -6,28 +6,28 @@ import (
)
func (w *Wasm) ExecLocal_Create(payload *types2.WasmCreate, tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return execLocal(receipt)
return &types.LocalDBSet{}, nil
}
func (w *Wasm) ExecLocal_Call(payload *types2.WasmCall, tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return execLocal(receipt)
}
func execLocal(receipt *types.ReceiptData) (*types.LocalDBSet, error) {
if receipt.Ty != types.ExecOk {
return nil, nil
return &types.LocalDBSet{}, nil
}
set := &types.LocalDBSet{}
localExecer := w.userExecName(payload.Contract, true)
var KVs []*types.KeyValue
for _, item := range receipt.Logs {
if item.Ty == types2.TyLogLocalData {
var data types2.LocalDataLog
err := types.Decode(item.Log, &data)
if err != nil {
log.Error("execLocal", "decode error", err)
continue
return nil, err
}
set.KV = append(set.KV, &types.KeyValue{Key: data.Key, Value: data.CurValue})
KVs = append(KVs, &types.KeyValue{
Key: data.Key,
Value: data.Value,
})
}
}
return set, nil
return &types.LocalDBSet{KV: w.AddRollbackKV(tx, []byte(localExecer), KVs)}, nil
}
......@@ -2,6 +2,7 @@ package executor
import (
"github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/system/dapp"
drivers "github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
types2 "github.com/33cn/plugin/plugin/dapp/wasm/types"
......@@ -28,11 +29,13 @@ type Wasm struct {
drivers.DriverBase
tx *types.Transaction
stateKVC *dapp.KVCreator
localCache []*types2.LocalDataLog
kvs []*types.KeyValue
receiptLogs []*types.ReceiptLog
logs []string
customLogs []string
execAddr string
contractAddr string
contractName string
}
func newWasm() drivers.Driver {
......
......@@ -12,6 +12,8 @@ var NameReg *regexp.Regexp
const (
WasmX = "wasm"
NameRegExp = "^[a-z0-9]+$"
//TODO: max size to define
MaxCodeSize = 1 << 20
)
// action for executor
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment