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

update wasm with chain33 plugin framework

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