Commit a4b37c31 authored by 袁兴强's avatar 袁兴强

wasm contract can be updated by the creator

parent a980fd5d
......@@ -23,6 +23,7 @@ func Cmd() *cobra.Command {
cmd.AddCommand(
cmdCheckContract(),
cmdCreateContract(),
cmdUpdateContract(),
cmdCallContract(),
)
......@@ -53,6 +54,19 @@ func cmdCreateContract() *cobra.Command {
return cmd
}
func cmdUpdateContract() *cobra.Command {
cmd := &cobra.Command{
Use: "update",
Short: "update an existing contract on chain33",
Run: updateContract,
}
cmd.Flags().StringP("name", "n", "", "contract name")
cmd.Flags().StringP("path", "p", "", "path of the wasm file, such as ./test.wasm")
_ = cmd.MarkFlagRequired("name")
_ = cmd.MarkFlagRequired("path")
return cmd
}
func cmdCallContract() *cobra.Command {
cmd := &cobra.Command{
Use: "call",
......@@ -110,6 +124,31 @@ func createContract(cmd *cobra.Command, args []string) {
ctx.RunWithoutMarshal()
}
func updateContract(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
name, _ := cmd.Flags().GetString("name")
path, _ := cmd.Flags().GetString("path")
// Read WebAssembly *.wasm file.
code, err := ioutil.ReadFile(path)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
payload := wasmtypes.WasmUpdate{
Name: name,
Code: code,
}
params := rpctypes.CreateTxIn{
Execer: wasmtypes.WasmX,
ActionName: "Update",
Payload: types.MustPBToJSON(&payload),
}
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, nil)
ctx.RunWithoutMarshal()
}
func callContract(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
name, _ := cmd.Flags().GetString("name")
......
......@@ -55,9 +55,16 @@ wabt/bin/wasm2wat dice.wasm
### 发布合约
```bash
# 若合约已存在则会创建失败,可以换一个合约名发布
./chain33-cli send wasm create -n 指定合约名 -p wasm合约路径 -k 用户私钥
```
### 更新合约
```bash
# 更新合约要求合约已存在,且只有合约创建者有更新权限
./chain33-cli send wasm update -n 指定合约名 -p wasm合约路径 -k 用户私钥
```
### 调用合约
```bash
#其中参数为用逗号分隔的数字列表,字符串参数为逗号分隔的字符串列表
......
......@@ -10,6 +10,11 @@ func contractKey(name string) []byte {
return append([]byte("mavl-"+types2.WasmX+"-code-"), []byte(name)...)
}
// "mavl-wasm-creator-{name}"
func contractCreatorKey(name string) []byte {
return append([]byte("mavl-"+types2.WasmX+"-creator-"), []byte(name)...)
}
// "mavl-wasm-{contract}-"
func calcStatePrefix(contract string) []byte {
var prefix []byte
......
......@@ -48,7 +48,7 @@ func (w *Wasm) Exec_Create(payload *types2.WasmCreate, tx *types.Transaction, in
return nil, types2.ErrInvalidWasm
}
kvc := dapp.NewKVCreator(w.GetStateDB(), nil, nil)
kvc := dapp.NewKVCreator(w.GetStateDB(), types.CalcStatePrefix(tx.Execer), nil)
_, err := kvc.GetNoPrefix(contractKey(name))
if err == nil {
return nil, types2.ErrContractExist
......@@ -57,6 +57,7 @@ func (w *Wasm) Exec_Create(payload *types2.WasmCreate, tx *types.Transaction, in
return nil, err
}
kvc.AddNoPrefix(contractKey(name), code)
kvc.AddNoPrefix(contractCreatorKey(name), []byte(tx.From()))
receiptLog := &types.ReceiptLog{
Ty: types2.TyLogWasmCreate,
......@@ -73,6 +74,53 @@ func (w *Wasm) Exec_Create(payload *types2.WasmCreate, tx *types.Transaction, in
}, nil
}
func (w *Wasm) Exec_Update(payload *types2.WasmUpdate, 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
kvc := dapp.NewKVCreator(w.GetStateDB(), types.CalcStatePrefix(tx.Execer), nil)
creator, err := kvc.GetNoPrefix(contractCreatorKey(name))
if err != nil {
return nil, types2.ErrContractNotExist
}
_, err = kvc.GetNoPrefix(contractKey(name))
if err != nil {
return nil, types2.ErrContractNotExist
}
if tx.From() != string(creator) {
return nil, types2.ErrInvalidCreator
}
code := payload.Code
if len(code) > types2.MaxCodeSize {
return nil, types2.ErrCodeOversize
}
if err := validation.ValidateWasm(code); err != nil {
return nil, types2.ErrInvalidWasm
}
kvc.AddNoPrefix(contractKey(name), code)
receiptLog := &types.ReceiptLog{
Ty: types2.TyLogWasmUpdate,
Log: types.Encode(&types2.UpdateContractLog{
Name: name,
Code: hex.EncodeToString(code),
}),
}
return &types.Receipt{
Ty: types.ExecOk,
KV: kvc.KVList(),
Logs: []*types.ReceiptLog{receiptLog},
}, nil
}
func (w *Wasm) Exec_Call(payload *types2.WasmCall, tx *types.Transaction, index int) (*types.Receipt, error) {
if payload == nil {
return nil, types.ErrInvalidParam
......
......@@ -9,6 +9,10 @@ func (w *Wasm) ExecDelLocal_Create(payload *types2.WasmCreate, tx *types.Transac
return &types.LocalDBSet{}, nil
}
func (w *Wasm) ExecDelLocal_Update(payload *types2.WasmUpdate, tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return &types.LocalDBSet{}, nil
}
func (w *Wasm) ExecDelLocal_Call(payload *types2.WasmCall, tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
localExecer := w.userExecName(payload.Contract, true)
kvs, err := w.DelRollbackKV(tx, []byte(localExecer))
......
......@@ -9,6 +9,10 @@ func (w *Wasm) ExecLocal_Create(payload *types2.WasmCreate, tx *types.Transactio
return &types.LocalDBSet{}, nil
}
func (w *Wasm) ExecLocal_Update(payload *types2.WasmUpdate, tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return &types.LocalDBSet{}, nil
}
func (w *Wasm) ExecLocal_Call(payload *types2.WasmCall, tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
if receipt.Ty != types.ExecOk {
return &types.LocalDBSet{}, nil
......
......@@ -5,9 +5,10 @@ package types;
message wasmAction {
oneof value {
wasmCreate create = 1;
wasmCall call = 2;
wasmUpdate update = 2;
wasmCall call = 3;
}
int32 ty = 3;
int32 ty = 4;
}
message wasmCreate {
......@@ -15,6 +16,11 @@ message wasmCreate {
bytes code = 2;
}
message wasmUpdate {
string name = 1;
bytes code = 2;
}
message wasmCall {
string contract = 1;
string method = 2;
......@@ -35,6 +41,11 @@ message createContractLog {
string code = 2;
}
message updateContractLog {
string name = 1;
string code = 2;
}
message callContractLog {
string contract = 1;
string method = 2;
......
......@@ -3,7 +3,9 @@ package types
import "errors"
var (
ErrContractExist = errors.New("contract exist")
ErrContractExist = errors.New("contract already exist")
ErrContractNotExist = errors.New("contract not exist")
ErrInvalidCreator = errors.New("invalid contract creator")
ErrInvalidWasm = errors.New("invalid wasm code")
ErrCodeOversize = errors.New("code oversize")
ErrInvalidMethod = errors.New("invalid method")
......
......@@ -19,12 +19,14 @@ const (
// action for executor
const (
WasmActionCreate = iota + 1
WasmActionUpdate
WasmActionCall
)
// log ty for executor
const (
TyLogWasmCreate = iota + 100
TyLogWasmUpdate
TyLogWasmCall
TyLogCustom
TyLogLocalData
......@@ -64,6 +66,7 @@ func (t *WasmType) GetPayload() types.Message {
func (t *WasmType) GetTypeMap() map[string]int32 {
return map[string]int32{
"Create": WasmActionCreate,
"Update": WasmActionUpdate,
"Call": WasmActionCall,
}
}
......@@ -71,6 +74,7 @@ func (t *WasmType) GetTypeMap() map[string]int32 {
func (t *WasmType) GetLogMap() map[int64]*types.LogInfo {
return map[int64]*types.LogInfo{
TyLogWasmCreate: {Ty: reflect.TypeOf(CreateContractLog{}), Name: "LogWasmCreate"},
TyLogWasmUpdate: {Ty: reflect.TypeOf(UpdateContractLog{}), Name: "LogWasmUpdate"},
TyLogWasmCall: {Ty: reflect.TypeOf(CallContractLog{}), Name: "LogWasmCall"},
TyLogCustom: {Ty: reflect.TypeOf(CustomLog{}), Name: "LogWasmCustom"},
TyLogLocalData: {Ty: reflect.TypeOf(LocalDataLog{}), Name: "LogWasmLocalData"},
......
This diff is collapsed.
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