新注册的用户请输入邮箱并保存,随后登录邮箱激活账号。后续可直接使用邮箱登录!

Commit e7219ed0 authored by tianle's avatar tianle

Merge branch 'v2.3.1_qc' into 'develop' (merge request !32)

v2.3.1_qc
parents cb34b71d 5d823605
# IDE
.idea
.vscode
.DS_Store
cover.out
# tmp
*.log
*.log.*
.idea/*
\ No newline at end of file
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
\ No newline at end of file
gen:
cd pb/proto && protoc -I=. --gogofaster_out=plugins=grpc:../protogo --gogofaster_opt=paths=source_relative dms_message.proto
cd pb/proto && protoc -I=. --gogofaster_out=plugins=grpc:../protogo --gogofaster_opt=paths=source_relative dockervm_message.proto
mockgen:
mockgen -destination ./sdk/mock_sdk_interface.go -package sdk -source ./sdk/sdk_interface.go
mockgen-dep:
go get -u github.com/golang/mock/gomock
go get -u github.com/golang/mock/mockgen
\ No newline at end of file
长安链·ChainMaker
Copyright 2022 contributors to 长安链·ChainMaker
\ No newline at end of file
......@@ -6,10 +6,9 @@ if [ ! -d $DIR ]; then
mkdir -p $DIR
fi
echo "please input contract name, contract name should be same as name in tx: "
read contract_name
echo "please input zip file: "
echo "please input zip file name (no suffix): "
read zip_file
go build -o $contract_name
7z a $zip_file $contract_name
go build -ldflags="-s -w" -o $zip_file
7z a $zip_file $zip_file
mv $zip_file.7z $DIR
\ No newline at end of file
/*
Copyright (C) BABEC. All rights reserved.
Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
SPDX-License-Identifier: Apache-2.0
*/
package demo
import (
"encoding/hex"
"fmt"
"log"
"strconv"
"strings"
"chainmaker.org/chainmaker/common/v2/evmutils/abi"
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sandbox"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sdk"
)
type CrossEvmContract struct {
}
func (c *CrossEvmContract) InitContract() protogo.Response {
return sdk.Success([]byte("Init success"))
}
func (c *CrossEvmContract) UpgradeContract() protogo.Response {
return sdk.Success([]byte("Upgrade success"))
}
func (c *CrossEvmContract) InvokeContract(method string) protogo.Response {
switch method {
case "crossEvmStorageSet":
return c.CrossEvmStorageSet()
case "crossEvmStorageGet":
return c.CrossEvmStorageGet()
default:
return sdk.Error("invalid method")
}
}
func (c *CrossEvmContract) CrossEvmStorageSet() protogo.Response {
// 获取所有参数
args := sdk.Instance.GetArgs()
// 取出 storage abi
storateABIJson := string(args["storage_abi"])
storageAbi, err := abi.JSON(strings.NewReader(string(storateABIJson)))
if err != nil {
return sdk.Error(err.Error())
}
// 取出 data的10进制字符串表示
dataStr := string(args["storage_set_data"])
// dataStr 转换成 int64
data, err := strconv.ParseInt(dataStr, 10, 64)
if err != nil {
return sdk.Error(err.Error())
}
// 取出跨合约调用的方法
evmStorageFuncName := string(args["storage_set_func_name"])
dataByte, err := storageAbi.Pack(evmStorageFuncName, data)
if err != nil {
return sdk.Error(err.Error())
}
dataString := hex.EncodeToString(dataByte)
method := dataString[0:8]
// 取出 evm storage 合约名
storageContractName := string(args["storage_contract_name"])
crossContractArgs := make(map[string][]byte)
crossContractArgs["data"] = []byte(dataString)
// response could be correct or error
response := sdk.Instance.CallContract(storageContractName, method, crossContractArgs)
sdk.Instance.EmitEvent("cross contract set", []string{"success"})
return response
}
func (c *CrossEvmContract) CrossEvmStorageGet() protogo.Response {
// 获取所有参数
args := sdk.Instance.GetArgs()
// 取出 storage abi
storateABIJson := string(args["storage_abi"])
storageAbi, err := abi.JSON(strings.NewReader(string(storateABIJson)))
if err != nil {
return sdk.Error(err.Error())
}
// 取出跨合约调用的方法
evmStorageFuncName := string(args["storage_get_func_name"])
dataByte, err := storageAbi.Pack(evmStorageFuncName)
// dataByte, err := storageAbi.Pack("get")
if err != nil {
if err.Error() != "contract does not have a constructor" {
return sdk.Error(err.Error())
}
}
dataString := hex.EncodeToString(dataByte)
method := dataString[0:8]
// 取出 evm storage 合约名
storageContractName := string(args["storage_contract_name"])
crossContractArgs := make(map[string][]byte)
crossContractArgs["data"] = []byte(dataString)
// response could be correct or error
response := sdk.Instance.CallContract(storageContractName, method, crossContractArgs)
val, err := storageAbi.Unpack(evmStorageFuncName, response.Payload)
if err != nil {
return sdk.Error(err.Error())
}
sdk.Instance.EmitEvent("cross contract get", []string{fmt.Sprintf("%s", val)})
// return response
return sdk.Success([]byte(fmt.Sprintf("get value from evm: %s", val)))
}
func main() {
err := sandbox.Start(new(CrossEvmContract))
if err != nil {
log.Fatal(err)
}
}
......@@ -8,60 +8,59 @@ SPDX-License-Identifier: Apache-2.0
package demo
import (
"fmt"
"log"
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
"chainmaker.org/chainmaker/contract-sdk-go/v2/shim"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sandbox"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sdk"
)
type ContractCut struct {
}
func (t *ContractCut) InitContract(stub shim.CMStubInterface) protogo.Response {
return shim.Success([]byte("Init Success"))
func (c *ContractCut) InitContract() protogo.Response {
return sdk.Success([]byte("Init success"))
}
func (t *ContractCut) InvokeContract(stub shim.CMStubInterface) protogo.Response {
func (c *ContractCut) UpgradeContract() protogo.Response {
return sdk.Success([]byte("Upgrade success"))
}
args := stub.GetArgs()
func (c *ContractCut) InvokeContract(method string) protogo.Response {
method := string(args["method"])
switch method {
case "save":
return t.save(stub)
return c.Save()
case "findByFileHash":
return t.findByFileHash(stub)
return c.FindByFileHash()
default:
msg := fmt.Sprintf("unknown method")
return shim.Error(msg)
return sdk.Error("invalid method")
}
}
func (t *ContractCut) save(stub shim.CMStubInterface) protogo.Response {
key := string(stub.GetArgs()["file_key"])
name := stub.GetArgs()["file_name"]
func (c *ContractCut) Save() protogo.Response {
key := string(sdk.Instance.GetArgs()["file_key"])
name := sdk.Instance.GetArgs()["file_name"]
err := stub.PutStateByte(key, "", name)
err := sdk.Instance.PutStateByte(key, "", name)
if err != nil {
return shim.Error("fail to save")
return sdk.Error("fail to save")
}
return shim.Success([]byte("success"))
return sdk.Success([]byte("success"))
}
func (t *ContractCut) findByFileHash(stub shim.CMStubInterface) protogo.Response {
key := string(stub.GetArgs()["file_key"])
func (c *ContractCut) FindByFileHash() protogo.Response {
key := string(sdk.Instance.GetArgs()["file_key"])
_, err := stub.GetStateByte(key, "")
_, err := sdk.Instance.GetStateByte(key, "")
if err != nil {
return shim.Error("fail to find")
return sdk.Error("fail to find")
}
return shim.Success([]byte("success"))
return sdk.Success([]byte("success"))
}
func main() {
err := shim.Start(new(ContractCut))
err := sandbox.Start(new(ContractCut))
if err != nil {
log.Fatal(err)
}
......
......@@ -13,12 +13,33 @@ import (
"strconv"
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
"chainmaker.org/chainmaker/contract-sdk-go/v2/shim"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sandbox"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sdk"
)
type FactContract struct {
}
func (f *FactContract) InitContract() protogo.Response {
return sdk.Success([]byte("Init success"))
}
func (f *FactContract) UpgradeContract() protogo.Response {
return sdk.Success([]byte("Upgrade success"))
}
func (f *FactContract) InvokeContract(method string) protogo.Response {
switch method {
case "save":
return f.Save()
case "findByFileHash":
return f.FindByFileHash()
default:
return sdk.Error("invalid method")
}
}
// 存证对象
type Fact struct {
FileHash string `json:"FileHash"`
......@@ -36,30 +57,8 @@ func NewFact(FileHash string, FileName string, time int32) *Fact {
return fact
}
func (f *FactContract) InitContract(stub shim.CMStubInterface) protogo.Response {
return shim.Success([]byte("Init Success"))
}
func (f *FactContract) InvokeContract(stub shim.CMStubInterface) protogo.Response {
// 获取参数
method := string(stub.GetArgs()["method"])
switch method {
case "save":
return f.save(stub)
case "findByFileHash":
return f.findByFileHash(stub)
default:
return shim.Error("invalid method")
}
}
func (f *FactContract) save(stub shim.CMStubInterface) protogo.Response {
params := stub.GetArgs()
func (f *FactContract) Save() protogo.Response {
params := sdk.Instance.GetArgs()
// 获取参数
fileHash := string(params["file_hash"])
......@@ -68,8 +67,8 @@ func (f *FactContract) save(stub shim.CMStubInterface) protogo.Response {
time, err := strconv.Atoi(timeStr)
if err != nil {
msg := "time is [" + timeStr + "] not int"
stub.Log(msg)
return shim.Error(msg)
sdk.Instance.Debugf(msg)
return sdk.Error(msg)
}
// 构建结构体
......@@ -79,31 +78,31 @@ func (f *FactContract) save(stub shim.CMStubInterface) protogo.Response {
factBytes, _ := json.Marshal(fact)
// 发送事件
stub.EmitEvent("topic_vx", []string{fact.FileHash, fact.FileName})
sdk.Instance.EmitEvent("topic_vx", []string{fact.FileHash, fact.FileName})
// 存储数据
err = stub.PutStateByte("fact_bytes", fact.FileHash, factBytes)
err = sdk.Instance.PutStateByte("fact_bytes", fact.FileHash, factBytes)
if err != nil {
return shim.Error("fail to save fact bytes")
return sdk.Error("fail to save fact bytes")
}
// 记录日志
stub.Log("[save] FileHash=" + fact.FileHash)
stub.Log("[save] FileName=" + fact.FileName)
sdk.Instance.Debugf("[save] FileHash=" + fact.FileHash)
sdk.Instance.Debugf("[save] FileName=" + fact.FileName)
// 返回结果
return shim.Success([]byte(fact.FileName + fact.FileHash))
return sdk.Success([]byte(fact.FileName + fact.FileHash))
}
func (f *FactContract) findByFileHash(stub shim.CMStubInterface) protogo.Response {
func (f *FactContract) FindByFileHash() protogo.Response {
// 获取参数
FileHash := string(stub.GetArgs()["file_hash"])
FileHash := string(sdk.Instance.GetArgs()["file_hash"])
// 查询结果
result, err := stub.GetStateByte("fact_bytes", FileHash)
result, err := sdk.Instance.GetStateByte("fact_bytes", FileHash)
if err != nil {
return shim.Error("failed to call get_state")
return sdk.Error("failed to call get_state")
}
// 反序列化
......@@ -111,16 +110,16 @@ func (f *FactContract) findByFileHash(stub shim.CMStubInterface) protogo.Respons
_ = json.Unmarshal(result, &fact)
// 记录日志
stub.Log("[find_by_file_hash] FileHash=" + fact.FileHash)
stub.Log("[find_by_file_hash] FileName=" + fact.FileName)
sdk.Instance.Debugf("[find_by_file_hash] FileHash=" + fact.FileHash)
sdk.Instance.Debugf("[find_by_file_hash] FileName=" + fact.FileName)
// 返回结果
return shim.Success(result)
return sdk.Success(result)
}
func main() {
err := shim.Start(new(FactContract))
err := sandbox.Start(new(FactContract))
if err != nil {
log.Fatal(err)
}
......
/*
Copyright (C) BABEC. All rights reserved.
Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
SPDX-License-Identifier: Apache-2.0
*/
package demo
import (
"log"
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sandbox"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sdk"
)
type ContractFactCut struct {
}
func (c *ContractFactCut) InitContract() protogo.Response {
return sdk.Success([]byte("Init success"))
}
func (c *ContractFactCut) UpgradeContract() protogo.Response {
return sdk.Success([]byte("Upgrade success"))
}
func (c *ContractFactCut) InvokeContract(method string) protogo.Response {
switch method {
case "save":
return c.Save()
case "findByFileHash":
return c.FindByFileHash()
default:
return sdk.Error("invalid method")
}
}
func (c *ContractFactCut) Save() protogo.Response {
key := string(sdk.Instance.GetArgs()["file_key"])
name := sdk.Instance.GetArgs()["file_name"]
err := sdk.Instance.PutStateByte(key, "", name)
if err != nil {
return sdk.Error("fail to save")
}
return sdk.Success([]byte("success"))
}
func (c *ContractFactCut) FindByFileHash() protogo.Response {
key := string(sdk.Instance.GetArgs()["file_key"])
_, err := sdk.Instance.GetStateByte(key, "")
if err != nil {
return sdk.Error("fail to find")
}
return sdk.Success([]byte(""))
}
func main() {
err := sandbox.Start(new(ContractFactCut))
if err != nil {
log.Fatal(err)
}
}
This diff is collapsed.
......@@ -13,140 +13,121 @@ import (
"log"
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
"chainmaker.org/chainmaker/contract-sdk-go/v2/shim"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sandbox"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sdk"
)
type RaffleContract struct {
}
//type Peoples struct {
// Peoples map[string]int `json:"peoples"`
//}
type People struct {
Num int `json:"num"`
Name string `json:"name"`
func (r *RaffleContract) InitContract() protogo.Response {
return sdk.Success([]byte("Init success"))
}
type Peoples struct {
//Peoples map[int]string `json:"peoples"`
Peoples []*People `json:"peoples"`
func (r *RaffleContract) UpgradeContract() protogo.Response {
return sdk.Success([]byte("Upgrade success"))
}
func (f *RaffleContract) InitContract(stub shim.CMStubInterface) protogo.Response {
return shim.Success([]byte("Init Success"))
}
func (r *RaffleContract) InvokeContract(method string) protogo.Response {
func (f *RaffleContract) InvokeContract(stub shim.CMStubInterface) protogo.Response {
method := string(stub.GetArgs()["method"])
switch method {
//case "register":
// return f.register(stub)
case "registerAll":
return f.registerAll(stub)
case "query":
return f.query(stub)
//case "raffle":
// return f.raffle(stub)
case "register_all":
return r.RegisterAll()
case "raffle":
return f.raffle(stub)
return r.Raffle()
case "query":
return r.query()
default:
return shim.Error("invalid method")
return sdk.Error("invalid method")
}
}
func (f *RaffleContract) registerAll(stub shim.CMStubInterface) protogo.Response {
params := stub.GetArgs()
//type Peoples struct {
// Peoples map[string]int `json:"peoples"`
//}
type Peoples struct {
Peoples map[int]string `json:"peoples"`
}
func (r *RaffleContract) RegisterAll() protogo.Response {
params := sdk.Instance.GetArgs()
// 获取参数
value := params["peoples"]
var errMsg string
if len(value) == 0 {
errMsg = "value should not be empty!"
stub.Log(errMsg)
return shim.Error(errMsg)
sdk.Instance.Debugf(errMsg)
return sdk.Error(errMsg)
}
var peoples Peoples
err := json.Unmarshal(value, &peoples)
for i := 0; i < len(peoples.Peoples); i++ {
if people := peoples.Peoples[i]; len(people.Name) == 0 {
for i := 1; i < len(peoples.Peoples); i++ {
if name, ok := peoples.Peoples[i]; !ok || len(name) == 0 {
errMsg = fmt.Sprintf("[registerAll] name should not be empty for number %d", i)
stub.Log(errMsg)
return shim.Error(errMsg)
sdk.Instance.Debugf(errMsg)
return sdk.Error(errMsg)
}
}
err = stub.PutStateByte("peoples", "", value)
err = sdk.Instance.PutStateByte("peoples", "", value)
if err != nil {
errMsg = fmt.Sprintf("[registerAll] put state bytes failed, %s", err)
stub.Log(errMsg)
return shim.Error(errMsg)
errMsg = fmt.Sprintf("[register] put state bytes failed, %s", err)
sdk.Instance.Debugf(errMsg)
return sdk.Error(errMsg)
}
// 返回结果
return shim.Success([]byte("ok"))
return sdk.Success([]byte("ok"))
}
func (f *RaffleContract) raffle(stub shim.CMStubInterface) protogo.Response {
params := stub.GetArgs()
func (r *RaffleContract) Raffle() protogo.Response {
params := sdk.Instance.GetArgs()
var errMsg string
level := string(params["level"])
if len(level) == 0 {
errMsg = "level should not be empty!"
stub.Log(errMsg)
return shim.Error(errMsg)
}
argTimestamp := string(params["timestamp"])
if len(argTimestamp) == 0 {
errMsg = "argTimestamp should not be empty!"
stub.Log(errMsg)
return shim.Error(errMsg)
sdk.Instance.Debugf(errMsg)
return sdk.Error(errMsg)
}
peoplesData, err := stub.GetStateByte("peoples", "")
peoplesData, err := sdk.Instance.GetStateByte("peoples", "")
if err != nil {
errMsg = "get peoples data from store failed!"
stub.Log(errMsg)
return shim.Error(errMsg)
sdk.Instance.Debugf(errMsg)
return sdk.Error(errMsg)
}
var peoples Peoples
err = json.Unmarshal(peoplesData, &peoples)
if err != nil {
errMsg = fmt.Sprintf("unmarshal peoples data failed, %s", err)
stub.Log(errMsg)
return shim.Error(errMsg)
sdk.Instance.Debugf(errMsg)
return sdk.Error(errMsg)
}
num := f.bkdrHash(argTimestamp)
num := r.BkdrHash(argTimestamp)
num = num % len(peoples.Peoples)
stub.Log(fmt.Sprintf("raffle pos: %d", num))
resultPeople := peoples.Peoples[num]
result := fmt.Sprintf("num: %d, name: %s, level: %s", resultPeople.Num, resultPeople.Name, level)
var newPeoples Peoples
newPeoples.Peoples = append(newPeoples.Peoples, peoples.Peoples[0:num]...)
if num+1 < len(peoples.Peoples) {
newPeoples.Peoples = append(newPeoples.Peoples, peoples.Peoples[num+1:]...)
}
//delete(peoples.Peoples, num)
newPeoplesData, err := json.Marshal(newPeoples)
result := fmt.Sprintf("num: %d, name: %s", num, peoples.Peoples[num])
delete(peoples.Peoples, num)
newPeoplesData, err := json.Marshal(peoples.Peoples)
if err != nil {
errMsg = fmt.Sprintf("marshal new peoples data failed, %s", err)
stub.Log(errMsg)
return shim.Error(errMsg)
sdk.Instance.Debugf(errMsg)
return sdk.Error(errMsg)
}
err = stub.PutStateByte("peoples", "", newPeoplesData)
err = sdk.Instance.PutStateByte("peoples", "", newPeoplesData)
if err != nil {
errMsg = fmt.Sprintf("put new peoples data failed, %s", err)
stub.Log(errMsg)
return shim.Error(errMsg)
sdk.Instance.Debugf(errMsg)
return sdk.Error(errMsg)
}
return shim.Success([]byte(result))
return sdk.Success([]byte(result))
}
func (f *RaffleContract) bkdrHash(timestamp string) int {
func (r *RaffleContract) BkdrHash(timestamp string) int {
hash := 0
seed := 131
for x := range timestamp {
......@@ -155,95 +136,95 @@ func (f *RaffleContract) bkdrHash(timestamp string) int {
return hash & 0x7FFFFFFF
}
func (f *RaffleContract) query(stub shim.CMStubInterface) protogo.Response {
peoplesData, err := stub.GetStateByte("peoples", "")
func (r *RaffleContract) query() protogo.Response {
peoplesData, err := sdk.Instance.GetStateByte("peoples", "")
if err != nil {
errMsg := "get peoples data from store failed!"
stub.Log(errMsg)
return shim.Error(errMsg)
sdk.Instance.Debugf(errMsg)
return sdk.Error(errMsg)
}
return shim.Success(peoplesData)
return sdk.Success(peoplesData)
}
//func (f *RaffleContract) register(stub shim.CMStubInterface) protogo.Response {
// params := stub.GetArgs()
//func (f *RaffleContract) register() protogo.Response {
// params := f.Sdk.GetArgs()
//
// // 获取参数
// name := string(params["name"])
// if len(name) == 0 {
// msg := "name should not be empty!"
// stub.Log(msg)
// return shim.Error(msg)
// f.Sdk.Debugf(msg)
// return sdk.Error(msg)
// }
//
// index := 0
// var errMsg string
// result, err := stub.GetState("index", "")
// result, err := f.Sdk.GetState("index", "")
// if err != nil {
// errMsg = fmt.Sprintf("[register] get index from store failed, %s", err)
// stub.Log(errMsg)
// return shim.Error(errMsg)
// f.Sdk.Debugf(errMsg)
// return sdk.Error(errMsg)
// }
// if len(result) != 0 {
// index, err = strconv.Atoi(result)
// }
// if err != nil {
// errMsg = fmt.Sprintf("[register] convert index failed, %s", err)
// stub.Log(errMsg)
// return shim.Error(errMsg)
// f.Sdk.Debugf(errMsg)
// return sdk.Error(errMsg)
// }
// if index == 0 {
// index = 100
// } else {
// index++
// }
// resultBytes, err := stub.GetStateByte("peoples", "")
// resultBytes, err := f.Sdk.GetStateByte("peoples", "")
// if err != nil {
// errMsg = fmt.Sprintf("[register] get peoples data failed, %s", err)
// stub.Log(errMsg)
// return shim.Error(errMsg)
// f.Sdk.Debugf(errMsg)
// return sdk.Error(errMsg)
// }
// var peoples Peoples
// if err = json.Unmarshal(resultBytes, &peoples); err != nil {
// errMsg = fmt.Sprintf("[register] unmarshal peoples failed, %s", err)
// stub.Log(errMsg)
// return shim.Error(errMsg)
// f.Sdk.Debugf(errMsg)
// return sdk.Error(errMsg)
// }
// _, ok := peoples.Peoples[name]
// if ok {
// errMsg = fmt.Sprintf("[register] %s has already been register", name)
// stub.Log(errMsg)
// return shim.Error(errMsg)
// f.Sdk.Debugf(errMsg)
// return sdk.Error(errMsg)
// }
// peoples.Peoples[name] = index
// peoplesBytes, err := json.Marshal(peoples)
// if err != nil {
// errMsg = fmt.Sprintf("[register] mashal peoples failed, %s", err)
// stub.Log(errMsg)
// return shim.Error(errMsg)
// f.Sdk.Debugf(errMsg)
// return sdk.Error(errMsg)
// }
// err = stub.PutStateByte("peoples", "", peoplesBytes)
// err = f.Sdk.PutStateByte("peoples", "", peoplesBytes)
// if err != nil {
// errMsg = fmt.Sprintf("[register] put state bytes failed, %s", err)
// stub.Log(errMsg)
// return shim.Error(errMsg)
// f.Sdk.Debugf(errMsg)
// return sdk.Error(errMsg)
// }
// indexStr := strconv.Itoa(index)
// err = stub.PutState("index", "", indexStr)
// err = f.Sdk.PutState("index", "", indexStr)
// if err != nil {
// errMsg = fmt.Sprintf("[register] put state bytes failed, %s", err)
// stub.Log(errMsg)
// return shim.Error(errMsg)
// f.Sdk.Debugf(errMsg)
// return sdk.Error(errMsg)
// }
//
// // 返回结果
// return shim.Success([]byte(indexStr))
// return sdk.Success([]byte(indexStr))
//}
func main() {
err := shim.Start(new(RaffleContract))
err := sandbox.Start(new(RaffleContract))
if err != nil {
log.Fatal(err)
}
......
......@@ -10,123 +10,123 @@ import (
"log"
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
"chainmaker.org/chainmaker/contract-sdk-go/v2/shim"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sandbox"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sdk"
)
type StoreMapContract struct {
}
func (f *StoreMapContract) InitContract(stub shim.CMStubInterface) protogo.Response {
return shim.Success([]byte("Init Success"))
func (s *StoreMapContract) InitContract() protogo.Response {
return sdk.Success([]byte("Init success"))
}
func (s *StoreMapContract) UpgradeContract() protogo.Response {
return sdk.Success([]byte("Upgrade success"))
}
func (f *StoreMapContract) InvokeContract(stub shim.CMStubInterface) protogo.Response {
// 获取参数
method := string(stub.GetArgs()["method"])
func (s *StoreMapContract) InvokeContract(method string) protogo.Response {
switch method {
case "set":
return f.set(stub)
return s.Set()
case "get":
return f.get(stub)
return s.Get()
case "del":
return f.del(stub)
case "exist":
return f.exist(stub)
return s.Del()
default:
return shim.Error("invalid method")
return sdk.Error("invalid method")
}
}
func (f *StoreMapContract) set(stub shim.CMStubInterface) protogo.Response {
func (s *StoreMapContract) Set() protogo.Response {
var err error
var storeMap *shim.StoreMap
var storeMap *sdk.StoreMap
var deep int64 = 3
m := "m1"
storeMap, err = shim.NewStoreMap(m, deep, stub)
storeMap, err = sdk.NewStoreMap(m, deep)
if err != nil {
return shim.Error(err.Error())
return sdk.Error(err.Error())
}
key := []string{"key1", "key2", "key3"}
value := []byte("value")
_, err = storeMap.Set(key, value, stub)
err = storeMap.Set(key, value)
if err != nil {
return shim.Error(err.Error())
return sdk.Error(err.Error())
}
return shim.Success([]byte("success"))
return sdk.Success([]byte("success"))
}
func (f *StoreMapContract) get(stub shim.CMStubInterface) protogo.Response {
func (s *StoreMapContract) Get() protogo.Response {
var err error
var storeMap *shim.StoreMap
var storeMap *sdk.StoreMap
var deep int64 = 3
m := "m1"
storeMap, err = shim.NewStoreMap(m, deep, stub)
storeMap, err = sdk.NewStoreMap(m, deep)
if err != nil {
return shim.Error(err.Error())
return sdk.Error(err.Error())
}
key := []string{"key1", "key2", "key3"}
_, err = storeMap.Get(key, stub)
_, err = storeMap.Get(key)
if err != nil {
return shim.Error(err.Error())
return sdk.Error(err.Error())
}
return shim.Success([]byte("success"))
return sdk.Success([]byte("success"))
}
func (f *StoreMapContract) del(stub shim.CMStubInterface) protogo.Response {
func (s *StoreMapContract) Del() protogo.Response {
var err error
var storeMap *shim.StoreMap
var storeMap *sdk.StoreMap
var deep int64 = 3
m := "m1"
storeMap, err = shim.NewStoreMap(m, deep, stub)
storeMap, err = sdk.NewStoreMap(m, deep)
if err != nil {
return shim.Error(err.Error())
return sdk.Error(err.Error())
}
key := []string{"key1", "key2", "key3"}
_, err = storeMap.Del(key, stub)
err = storeMap.Del(key)
if err != nil {
return shim.Error(err.Error())
return sdk.Error(err.Error())
}
return shim.Success([]byte("success"))
return sdk.Success([]byte("success"))
}
func (f *StoreMapContract) exist(stub shim.CMStubInterface) protogo.Response {
func (s *StoreMapContract) Exist() protogo.Response {
var err error
var storeMap *shim.StoreMap
var storeMap *sdk.StoreMap
var deep int64 = 3
m := "m1"
storeMap, err = shim.NewStoreMap(m, deep, stub)
storeMap, err = sdk.NewStoreMap(m, deep)
if err != nil {
return shim.Error(err.Error())
return sdk.Error(err.Error())
}
key := []string{"key1", "key2", "key3"}
_, err = storeMap.Exist(key, stub)
_, err = storeMap.Exist(key)
if err != nil {
return shim.Error(err.Error())
return sdk.Error(err.Error())
}
return shim.Success([]byte("success"))
return sdk.Success([]byte("success"))
}
func main() {
err := shim.Start(new(StoreMapContract))
err := sandbox.Start(new(StoreMapContract))
if err != nil {
log.Fatal(err)
}
......
......@@ -13,34 +13,35 @@ import (
"strconv"
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
"chainmaker.org/chainmaker/contract-sdk-go/v2/shim"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sandbox"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sdk"
)
type TransferContract struct {
}
func (t *TransferContract) InitContract(stub shim.CMStubInterface) protogo.Response {
return shim.Success([]byte("Init Success"))
func (t *TransferContract) InitContract() protogo.Response {
return sdk.Success([]byte("Init success"))
}
func (t *TransferContract) InvokeContract(stub shim.CMStubInterface) protogo.Response {
func (t *TransferContract) UpgradeContract() protogo.Response {
return sdk.Success([]byte("Upgrade success"))
}
args := stub.GetArgs()
func (t *TransferContract) InvokeContract(method string) protogo.Response {
method := string(args["method"])
switch method {
case "init":
return t.init(stub)
return t.Init()
case "transfer":
return t.transfer(stub)
return t.Transfer()
default:
msg := fmt.Sprintf("unknown method")
return shim.Error(msg)
return sdk.Error("invalid method")
}
}
func (t *TransferContract) init(stub shim.CMStubInterface) protogo.Response {
args := stub.GetArgs()
func (t *TransferContract) Init() protogo.Response {
args := sdk.Instance.GetArgs()
accFrom := string(args["accFrom"])
accTo := string(args["accTo"])
......@@ -50,86 +51,86 @@ func (t *TransferContract) init(stub shim.CMStubInterface) protogo.Response {
endIndex := string(args["end_index"]) // 分批创建账户 - end index
if !t.isNumber(fromBal) {
return shim.Error("from_bal is not a number")
return sdk.Error("from_bal is not a number")
}
if !t.isNumber(toBal) {
return shim.Error("to_bal is not a number")
return sdk.Error("to_bal is not a number")
}
start, err := strconv.Atoi(startIndex)
if err != nil {
return shim.Error("start index is not a number")
return sdk.Error("start index is not a number")
}
end, err := strconv.Atoi(endIndex)
if err != nil {
return shim.Error("end index is not a number")
return sdk.Error("end index is not a number")
}
if start > end {
return shim.Error("start index bigger than end index")
return sdk.Error("start index bigger than end index")
}
for i := start; i <= end; i++ {
newAccFrom := accFrom + strconv.Itoa(i)
newAccTo := accTo + strconv.Itoa(i)
err = stub.PutStateFromKey(newAccFrom, fromBal)
err = sdk.Instance.PutStateFromKey(newAccFrom, fromBal)
if err != nil {
return shim.Error(fmt.Sprintf("putState(%s, %s) err: %+v", newAccFrom, fromBal, err))
return sdk.Error(fmt.Sprintf("putState(%s, %s) err: %+v", newAccFrom, fromBal, err))
}
err = stub.PutStateFromKey(newAccTo, toBal)
err = sdk.Instance.PutStateFromKey(newAccTo, toBal)
if err != nil {
return shim.Error(fmt.Sprintf("putState(%s, %s) err: %+v", newAccTo, toBal, err))
return sdk.Error(fmt.Sprintf("putState(%s, %s) err: %+v", newAccTo, toBal, err))
}
}
return shim.Success([]byte("init success"))
return sdk.Success([]byte("init success"))
}
func (t *TransferContract) transfer(stub shim.CMStubInterface) protogo.Response {
args := stub.GetArgs()
func (t *TransferContract) Transfer() protogo.Response {
args := sdk.Instance.GetArgs()
accFrom := string(args["acc_from"])
accTo := string(args["acc_to"])
amtTrans, err := strconv.Atoi(string(args["amt_trans"]))
if err != nil {
return shim.Error("amt_trans is not a number")
return sdk.Error("amt_trans is not a number")
}
fromBalStr, err := stub.GetStateFromKey(accFrom)
fromBalStr, err := sdk.Instance.GetStateFromKey(accFrom)
if err != nil {
return shim.Error(fmt.Sprintf("getState(%s) error: %+v", accFrom, err))
return sdk.Error(fmt.Sprintf("getState(%s) error: %+v", accFrom, err))
}
fromBal, err := strconv.Atoi(fromBalStr)
if err != nil {
return shim.Error("from_bal is not a number")
return sdk.Error("from_bal is not a number")
}
toBalStr, err := stub.GetStateFromKey(accTo)
toBalStr, err := sdk.Instance.GetStateFromKey(accTo)
if err != nil {
return shim.Error(fmt.Sprintf("getState(%s) error: %+v", accTo, err))
return sdk.Error(fmt.Sprintf("getState(%s) error: %+v", accTo, err))
}
toBal, err := strconv.Atoi(toBalStr)
if err != nil {
return shim.Error("to_bal is not a number")
return sdk.Error("to_bal is not a number")
}
if fromBal < amtTrans {
return shim.Error(fmt.Sprintf("money doesn't enough, from_bal: %d, amt_trans: %d", fromBal, amtTrans))
return sdk.Error(fmt.Sprintf("money doesn't enough, from_bal: %d, amt_trans: %d", fromBal, amtTrans))
}
fromBal -= amtTrans
toBal += amtTrans
err = stub.PutStateFromKey(accFrom, strconv.Itoa(fromBal))
err = sdk.Instance.PutStateFromKey(accFrom, strconv.Itoa(fromBal))
if err != nil {
return shim.Error(fmt.Sprintf("putState(%s, %d) err: %+v", accFrom, fromBal, err))
return sdk.Error(fmt.Sprintf("putState(%s, %d) err: %+v", accFrom, fromBal, err))
}
err = stub.PutStateFromKey(accTo, strconv.Itoa(toBal))
err = sdk.Instance.PutStateFromKey(accTo, strconv.Itoa(toBal))
if err != nil {
return shim.Error(fmt.Sprintf("putState(%s, %d) err: %+v", accTo, toBal, err))
return sdk.Error(fmt.Sprintf("putState(%s, %d) err: %+v", accTo, toBal, err))
}
return shim.Success([]byte("transfer success"))
return sdk.Success([]byte("transfer success"))
}
func (t *TransferContract) isNumber(bal string) bool {
......@@ -141,7 +142,7 @@ func (t *TransferContract) isNumber(bal string) bool {
}
func main() {
err := shim.Start(new(TransferContract))
err := sandbox.Start(new(TransferContract))
if err != nil {
log.Fatal(err)
}
......
......@@ -12,63 +12,63 @@ import (
"log"
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
"chainmaker.org/chainmaker/contract-sdk-go/v2/shim"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sandbox"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sdk"
)
type Contract1 struct {
}
func (c *Contract1) InitContract(stub shim.CMStubInterface) protogo.Response {
return shim.Success([]byte("Init Success"))
func (c *Contract1) InitContract() protogo.Response {
return sdk.Success([]byte("Init success"))
}
func (c *Contract1) InvokeContract(stub shim.CMStubInterface) protogo.Response {
func (c *Contract1) UpgradeContract() protogo.Response {
return sdk.Success([]byte("Upgrade success"))
}
args := stub.GetArgs()
func (c *Contract1) InvokeContract(method string) protogo.Response {
method := string(args["method"])
switch method {
case "save":
return c.save(stub)
return c.Save()
case "find":
return c.find(stub)
return c.Find()
default:
msg := fmt.Sprintf("unknown method")
return shim.Error(msg)
return sdk.Error("invalid method")
}
}
func (c *Contract1) save(stub shim.CMStubInterface) protogo.Response {
params := stub.GetArgs()
func (c *Contract1) Save() protogo.Response {
params := sdk.Instance.GetArgs()
key := string(params["key"])
value := string(params["value"])
err := stub.PutStateFromKey(key, value)
err := sdk.Instance.PutStateFromKey(key, value)
if err != nil {
errMsg := fmt.Sprintf("fail to save key [%s], value [%s]: err: [%s]",
key, value, err)
return shim.Error(errMsg)
return sdk.Error(errMsg)
}
return shim.Success([]byte("successfully save"))
return sdk.Success([]byte("successfully save"))
}
func (c *Contract1) find(stub shim.CMStubInterface) protogo.Response {
params := stub.GetArgs()
func (c *Contract1) Find() protogo.Response {
params := sdk.Instance.GetArgs()
key := string(params["key"])
value, err := stub.GetStateFromKey(key)
value, err := sdk.Instance.GetStateFromKey(key)
if err != nil {
errMsg := fmt.Sprintf("fail to get key [%s], value [%s]: err: [%s]",
key, value, err)
return shim.Error(errMsg)
return sdk.Error(errMsg)
}
return shim.Success([]byte(value))
return sdk.Success([]byte(value))
}
func main() {
err := shim.Start(new(Contract1))
err := sandbox.Start(new(Contract1))
if err != nil {
log.Fatal(err)
}
......
......@@ -8,56 +8,54 @@ SPDX-License-Identifier: Apache-2.0
package demo
import (
"fmt"
"log"
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
"chainmaker.org/chainmaker/contract-sdk-go/v2/shim"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sandbox"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sdk"
)
type Contract2 struct {
}
func (c *Contract2) InitContract(stub shim.CMStubInterface) protogo.Response {
return shim.Success([]byte("Init Success"))
func (c *Contract2) InitContract() protogo.Response {
return sdk.Success([]byte("Init success"))
}
func (c *Contract2) InvokeContract(stub shim.CMStubInterface) protogo.Response {
func (c *Contract2) UpgradeContract() protogo.Response {
return sdk.Success([]byte("Upgrade success"))
}
args := stub.GetArgs()
func (c *Contract2) InvokeContract(method string) protogo.Response {
method := string(args["method"])
switch method {
case "display":
return c.display(stub)
case "cross_call":
return c.crossCall(stub)
return c.Display()
case "crossCall":
return c.CrossCall()
default:
msg := fmt.Sprintf("unknown method")
return shim.Error(msg)
return sdk.Error("invalid method")
}
}
func (c *Contract2) display(stub shim.CMStubInterface) protogo.Response {
return shim.Success([]byte("successfully display"))
func (c *Contract2) Display() protogo.Response {
return sdk.Success([]byte("successfully display"))
}
func (c *Contract2) crossCall(stub shim.CMStubInterface) protogo.Response {
func (c *Contract2) CrossCall() protogo.Response {
contractName := "contract1"
contractVersion := "1.0.0"
contractMethod := "find"
crossContractArgs := make(map[string][]byte)
crossContractArgs["method"] = []byte("find")
crossContractArgs["key"] = []byte("key")
result := stub.CallContract(contractName, contractVersion, crossContractArgs)
result := sdk.Instance.CallContract(contractName, contractMethod, crossContractArgs)
return result
}
func main() {
err := shim.Start(new(Contract2))
err := sandbox.Start(new(Contract2))
if err != nil {
log.Fatal(err)
}
......
module chainmaker.org/chainmaker/contract-sdk-go/v2
go 1.15
go 1.16
require (
chainmaker.org/chainmaker/common/v2 v2.2.0
chainmaker.org/chainmaker/pb-go/v2 v2.2.2-0.20220610071700-48769fb5638b
chainmaker.org/chainmaker/protocol/v2 v2.2.0
chainmaker.org/chainmaker/common/v2 v2.3.0
chainmaker.org/chainmaker/pb-go/v2 v2.3.0
chainmaker.org/chainmaker/protocol/v2 v2.3.0
github.com/gogo/protobuf v1.3.2
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.2
github.com/tjfoc/gmsm v1.4.1
go.uber.org/zap v1.18.1
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
google.golang.org/grpc v1.40.0
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
golang.org/x/tools v0.1.10 // indirect
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
google.golang.org/grpc v1.41.1
)
This diff is collapsed.
......@@ -13,12 +13,33 @@ import (
"strconv"
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
"chainmaker.org/chainmaker/contract-sdk-go/v2/shim"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sandbox"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sdk"
)
type FactContract struct {
}
func (f *FactContract) InitContract() protogo.Response {
return sdk.Success([]byte("init success"))
}
func (f *FactContract) UpgradeContract() protogo.Response {
return sdk.Success([]byte("upgrade success"))
}
func (f *FactContract) InvokeContract(method string) protogo.Response {
switch method {
case "save":
return f.save()
case "findByFileHash":
return f.findByFileHash()
default:
return sdk.Error("invalid method")
}
}
// 存证对象
type Fact struct {
FileHash string `json:"FileHash"`
......@@ -36,30 +57,8 @@ func NewFact(FileHash string, FileName string, time int32) *Fact {
return fact
}
func (f *FactContract) InitContract(stub shim.CMStubInterface) protogo.Response {
return shim.Success([]byte("Init Success"))
}
func (f *FactContract) InvokeContract(stub shim.CMStubInterface) protogo.Response {
// 获取参数
method := string(stub.GetArgs()["method"])
switch method {
case "save":
return f.save(stub)
case "findByFileHash":
return f.findByFileHash(stub)
default:
return shim.Error("invalid method")
}
}
func (f *FactContract) save(stub shim.CMStubInterface) protogo.Response {
params := stub.GetArgs()
func (f *FactContract) save() protogo.Response {
params := sdk.Instance.GetArgs()
// 获取参数
fileHash := string(params["file_hash"])
......@@ -68,8 +67,8 @@ func (f *FactContract) save(stub shim.CMStubInterface) protogo.Response {
time, err := strconv.Atoi(timeStr)
if err != nil {
msg := "time is [" + timeStr + "] not int"
stub.Log(msg)
return shim.Error(msg)
sdk.Instance.Debugf(msg)
return sdk.Error(msg)
}
// 构建结构体
......@@ -79,31 +78,31 @@ func (f *FactContract) save(stub shim.CMStubInterface) protogo.Response {
factBytes, _ := json.Marshal(fact)
// 发送事件
stub.EmitEvent("topic_vx", []string{fact.FileHash, fact.FileName})
sdk.Instance.EmitEvent("topic_vx", []string{fact.FileHash, fact.FileName})
// 存储数据
err = stub.PutStateByte("fact_bytes", fact.FileHash, factBytes)
err = sdk.Instance.PutStateByte("fact_bytes", fact.FileHash, factBytes)
if err != nil {
return shim.Error("fail to save fact bytes")
return sdk.Error("fail to save fact bytes")
}
// 记录日志
stub.Log("[save] FileHash=" + fact.FileHash)
stub.Log("[save] FileName=" + fact.FileName)
sdk.Instance.Debugf("[save] FileHash=" + fact.FileHash)
sdk.Instance.Debugf("[save] FileName=" + fact.FileName)
// 返回结果
return shim.Success([]byte(fact.FileName + fact.FileHash))
return sdk.Success([]byte(fact.FileName + fact.FileHash))
}
func (f *FactContract) findByFileHash(stub shim.CMStubInterface) protogo.Response {
func (f *FactContract) findByFileHash() protogo.Response {
// 获取参数
FileHash := string(stub.GetArgs()["file_hash"])
FileHash := string(sdk.Instance.GetArgs()["file_hash"])
// 查询结果
result, err := stub.GetStateByte("fact_bytes", FileHash)
result, err := sdk.Instance.GetStateByte("fact_bytes", FileHash)
if err != nil {
return shim.Error("failed to call get_state")
return sdk.Error("failed to call get_state")
}
// 反序列化
......@@ -111,16 +110,16 @@ func (f *FactContract) findByFileHash(stub shim.CMStubInterface) protogo.Respons
_ = json.Unmarshal(result, &fact)
// 记录日志
stub.Log("[find_by_file_hash] FileHash=" + fact.FileHash)
stub.Log("[find_by_file_hash] FileName=" + fact.FileName)
sdk.Instance.Debugf("[find_by_file_hash] FileHash=" + fact.FileHash)
sdk.Instance.Debugf("[find_by_file_hash] FileName=" + fact.FileName)
// 返回结果
return shim.Success(result)
return sdk.Success(result)
}
func main() {
err := shim.Start(new(FactContract))
err := sandbox.Start(new(FactContract))
if err != nil {
log.Fatal(err)
}
......
syntax = "proto3";
package proto;
option go_package = "chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo";
// manager as server - sandbox established a connection to the manager
service DMSRpc {
rpc DMSCommunicate(stream DMSMessage) returns (stream DMSMessage);
}
message DMSMessage {
string tx_id = 1;
DMSMessageType type = 2;
uint32 current_height = 3;
int32 result_code = 4;
bytes payload = 5;
string message = 6;
}
enum DMSMessageType {
DMS_MESSAGE_TYPE_UNDEFINED = 0;
DMS_MESSAGE_TYPE_REGISTER = 1;
DMS_MESSAGE_TYPE_REGISTERED = 2;
DMS_MESSAGE_TYPE_PREPARE = 3;
DMS_MESSAGE_TYPE_READY = 4;
DMS_MESSAGE_TYPE_INIT = 5;
DMS_MESSAGE_TYPE_INVOKE = 6;
DMS_MESSAGE_TYPE_GET_STATE_REQUEST = 7;
DMS_MESSAGE_TYPE_GET_STATE_RESPONSE = 8;
DMS_MESSAGE_TYPE_CALL_CONTRACT_REQUEST = 9;
DMS_MESSAGE_TYPE_CALL_CONTRACT_RESPONSE = 10;
DMS_MESSAGE_TYPE_COMPLETED = 11;
DMS_MESSAGE_TYPE_ERROR = 12;
DMS_MESSAGE_TYPE_CREATE_KV_ITERATOR_REQUEST = 13;
DMS_MESSAGE_TYPE_CREATE_KV_ITERATOR_RESPONSE = 14;
DMS_MESSAGE_TYPE_CONSUME_KV_ITERATOR_REQUEST = 15;
DMS_MESSAGE_TYPE_CONSUME_KV_ITERATOR_RESPONSE = 16;
DMS_MESSAGE_TYPE_CREATE_KEY_HISTORY_ITER_REQUEST= 17;
DMS_MESSAGE_TYPE_CREATE_KEY_HISTORY_ITER_RESPONSE = 18;
DMS_MESSAGE_TYPE_CONSUME_KEY_HISTORY_ITER_REQUEST= 19;
DMS_MESSAGE_TYPE_CONSUME_KEY_HISTORY_ITER_RESPONSE = 20;
DMS_MESSAGE_TYPE_GET_SENDER_ADDRESS_REQUEST = 21;
DMS_MESSAGE_TYPE_GET_SENDER_ADDRESS_RESPONSE = 22;
DMS_MESSAGE_TYPE_GET_BATCH_STATE_REQUEST = 23;
DMS_MESSAGE_TYPE_GET_BATCH_STATE_RESPONSE = 24;
}
// -------------------- request message ---------------------
message Input {
map<string, bytes> args = 1;
}
message CallContractRequest {
string contract_name = 1;
string contract_version = 2;
// args
map<string, bytes> args = 3;
}
// -------------------- result message ---------------------
// user method response
message Response {
// A status code that should follow the HTTP status codes.
int32 status = 1;
// A message associated with the response code. error has message
string message = 2;
// A payload that can be used to include metadata with this response. success with payload
bytes payload = 3;
}
// real user contract response
message ContractResponse {
// always has response
Response response = 1;
// always has write map
map<string, bytes> write_map = 2;
// only cross contracts has read map
map<string, bytes> read_map = 3;
// always has events
repeated Event events = 4;
}
message Event {
// Event topic
string topic = 1;
// Event contract name
string contract_name = 2;
// Event contract version
string contract_version = 3;
// Event payload
repeated string data = 4;
}
syntax = "proto3";
package proto;
option go_package = "chainmaker.org/chainmaker/contract-sdk-go/pb/protogo";
service DockerVMRpc {
rpc DockerVMCommunicate(stream DockerVMMessage) returns(stream DockerVMMessage) {};
}
//DockerVMMessage means message between chainmaker and docker vm
message DockerVMMessage {
string tx_id = 1;
DockerVMType type = 2;
CrossContext cross_context = 3;
// if not used, set to nil
SysCallMessage sys_call_message = 4;
// if not used, set to nil
TxRequest request = 5;
// if not used, set to nil
TxResponse response = 6;
string chain_id = 7;
repeated StepDuration step_durations = 8;
}
message SysCallMessage {
DockerVMCode code = 1;
string message = 2;
// if not used, set to nil
map<string, bytes> payload = 3;
}
message CrossContext {
uint32 current_depth = 1;
string process_name = 2;
/*
63 59 43 0
+----------+^-----------+-^---------+-^-------
| 4bits | 16bits | ..... | 4bits|
+----------+^-----------+-^---------+-^-------
depth_count | history_flag | vec<runtime_type>
the length of vec is controlled by depth_count
*/
uint64 cross_info = 3;
}
message StepDuration {
StepType type = 1;
int64 start_time = 2;
int64 step_duration = 3;
int64 until_duration = 4;
string msg = 5;
}
enum DockerVMType {
UNDEFINED = 0;
REGISTER = 1;
REGISTERED = 2;
PREPARE = 3;
READY = 4;
INIT = 5;
INVOKE = 6;
TX_REQUEST = 7;
TX_RESPONSE = 8;
GET_STATE_REQUEST = 9;
GET_STATE_RESPONSE = 10;
GET_BYTECODE_REQUEST = 11;
GET_BYTECODE_RESPONSE = 12;
CALL_CONTRACT_REQUEST = 13;
CALL_CONTRACT_RESPONSE = 14;
COMPLETED = 15;
ERROR = 16;
CREATE_KV_ITERATOR_REQUEST = 17;
CREATE_KV_ITERATOR_RESPONSE = 18;
CONSUME_KV_ITERATOR_REQUEST = 19;
CONSUME_KV_ITERATOR_RESPONSE = 20;
CREATE_KEY_HISTORY_ITER_REQUEST = 21;
CREATE_KEY_HISTORY_TER_RESPONSE = 22;
CONSUME_KEY_HISTORY_ITER_REQUEST = 23;
CONSUME_KEY_HISTORY_ITER_RESPONSE = 24;
GET_SENDER_ADDRESS_REQUEST = 25;
GET_SENDER_ADDRESS_RESPONSE = 26;
GET_BATCH_STATE_REQUEST = 27;
GET_BATCH_STATE_RESPONSE = 28;
}
enum StepType {
RUNTIME_PREPARE_TX_REQUEST = 0;
RUNTIME_GRPC_SEND_TX_REQUEST = 1;
ENGINE_GRPC_RECEIVE_TX_REQUEST = 2;
ENGINE_SCHEDULER_RECEIVE_TX_REQUEST = 3;
ENGINE_SCHEDULER_SEND_TX_REQUEST = 4;
ENGINE_GROUP_RECEIVE_TX_REQUEST = 5;
ENGINE_GROUP_SEND_TX_REQUEST = 6;
ENGINE_PROCESS_RECEIVE_TX_REQUEST = 7;
ENGINE_PROCESS_SEND_TX_REQUEST = 8;
ENGINE_PROCESS_RECEIVE_TX_RESPONSE = 9;
SANDBOX_GRPC_RECEIVE_TX_REQUEST = 10;
SANDBOX_GRPC_SEND_TX_REQUEST = 11;
SANDBOX_CHAN_SEND_TX_REQUEST = 12;
SANDBOX_HANDLER_RECEIVE_TX_REQUEST = 13;
SANDBOX_HANDLER_EXECUTE = 14;
SANDBOX_SEND_CHAIN_RESP = 15;
SANDBOX_GRPC_SEND_CHAIN_RESP = 16;
SANDBOX_SEND_ENGINE_RESP = 17;
RUNTIME_GRPC_RECEIVE_TX_RESPONSE = 18;
RUNTIME_GET_NOTIFY_TX_RESPONSE = 19;
RUNTIME_HANDLER_RECEIVE_TX_RESPONSE = 20;
RUNTIME_HANDLE_TX_RESPONSE = 21;
}
// TX_REQUEST
message TxRequest {
string contract_name = 1;
string contract_version = 2;
string method = 3;
map<string, bytes> parameters = 4;
// cross contract in use
TxContext tx_context = 5;
string chain_id = 6;
}
message TxContext {
map<string, bytes> write_map = 1;
map<string, bytes> read_map = 2;
}
// TX_RESPONSE
message TxResponse {
string tx_id = 1;
DockerVMCode code = 2;
bytes result = 3;
string message = 4;
map<string, bytes> write_map = 5;
map<string, bytes> read_map = 6;
repeated DockerContractEvent events = 7;
string contract_name = 8;
string contract_version = 9;
string chain_id = 10;
}
message DockerContractEvent {
// Event topic
string topic = 1;
// Event contract name
string contract_name = 2;
// Event payload
repeated string data = 3;
}
enum DockerVMCode {
OK = 0;
FAIL = 1;
}
// ============== DMS pb ==============
// -------------------- request message ---------------------
message CallContractRequest {
string contract_name = 1;
string contract_method = 2;
// args
map<string, bytes> args = 3;
}
// -------------------- result message ---------------------
// user method response
message Response {
// A status code that should follow the HTTP status codes.
int32 status = 1;
// A message associated with the response code. error has message
string message = 2;
// A payload that can be used to include metadata with this response. success with payload
bytes payload = 3;
}
// real user contract response
message ContractResponse {
// always has response
Response response = 1;
// always has write map
map<string, bytes> write_map = 2;
// only cross contracts has read map
map<string, bytes> read_map = 3;
// always has events
repeated Event events = 4;
}
message Event {
// Event topic
string topic = 1;
// Event contract name
string contract_name = 2;
// Event payload
repeated string data = 3;
}
This diff is collapsed.
This diff is collapsed.
/*
Copyright (C) BABEC. All rights reserved.
Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
SPDX-License-Identifier: Apache-2.0
*/
package sandbox
import (
"os"
"strconv"
"time"
)
const (
dialTimeout = 10 * time.Second
maxRecvMessageSize = 20 * 1024 * 1024 // 20 MiB
maxSendMessageSize = 20 * 1024 * 1024 // 20 MiB
runtimeSockFile = "/mount/runtime-sock/runtime.sock"
)
var config *Conf
type PRCProtocolType int
const (
UDS PRCProtocolType = iota
TCP
)
type Conf struct {
ProcessName string
ContractName string
LogLevel string
ContractEngineClient *ContractEngineClientConf
RuntimeClient *RuntimeClientConf
DisableSlowLog bool
}
type RuntimeClientConf struct {
RuntimeRPCProtocolType PRCProtocolType
RuntimeHost string
RuntimePort string
RuntimeUDSSockPath string
MaxSendMsgSize int
MaxRecvMsgSize int
}
type ContractEngineClientConf struct {
EngineUDSSockPath string
MaxSendMsgSize int
MaxRecvMsgSize int
}
func initConfig() error {
/*
Args:
UDSSockPath
ProcessName
ContractName
ContractVersion
LogLevel
TCPPort
Host
*/
config = &Conf{
ProcessName: os.Args[1],
ContractName: os.Args[2],
LogLevel: os.Args[4],
ContractEngineClient: &ContractEngineClientConf{
EngineUDSSockPath: os.Args[0],
MaxSendMsgSize: maxSendMessageSize,
MaxRecvMsgSize: maxRecvMessageSize,
},
RuntimeClient: &RuntimeClientConf{
MaxSendMsgSize: maxSendMessageSize,
MaxRecvMsgSize: maxRecvMessageSize,
},
}
port, err := strconv.Atoi(os.Args[5])
if err != nil {
return err
}
if isTCP(port) {
config.RuntimeClient.RuntimeRPCProtocolType = UDS
config.RuntimeClient.RuntimeUDSSockPath = runtimeSockFile
return nil
}
config.RuntimeClient.RuntimeRPCProtocolType = TCP
config.RuntimeClient.RuntimeHost = os.Args[6]
config.RuntimeClient.RuntimePort = strconv.Itoa(port)
if len(os.Args) > 7 {
if config.DisableSlowLog, err = strconv.ParseBool(os.Args[7]); err != nil {
return err
}
}
return nil
}
func isTCP(port int) bool {
return port == 0
}
/*
Copyright (C) BABEC. All rights reserved.
Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
SPDX-License-Identifier: Apache-2.0
*/
package sandbox
import (
"context"
"fmt"
"net"
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
"google.golang.org/grpc"
)
func newUDSClient() (protogo.DockerVMRpc_DockerVMCommunicateClient, error) {
dialOpts := []grpc.DialOption{
grpc.WithInsecure(),
grpc.WithContextDialer(func(ctx context.Context, sockAddress string) (net.Conn, error) {
unixAddress, err := net.ResolveUnixAddr("unix", sockAddress)
if err != nil {
return nil, err
}
return net.DialUnix("unix", nil, unixAddress)
}),
grpc.FailOnNonTempDialError(true),
grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(config.ContractEngineClient.MaxRecvMsgSize),
grpc.MaxCallSendMsgSize(config.ContractEngineClient.MaxRecvMsgSize),
),
grpc.WithWriteBufferSize(4 * 1024 * 1024),
grpc.WithReadBufferSize(4 * 1024 * 1024),
grpc.WithInitialWindowSize(64 * 1024 * 1024),
grpc.WithInitialConnWindowSize(64 * 1024 * 1024),
}
ctx, cancel := context.WithTimeout(context.Background(), dialTimeout)
defer cancel()
conn, err := grpc.DialContext(ctx, config.ContractEngineClient.EngineUDSSockPath, dialOpts...)
if err != nil {
return nil, err
}
return protogo.NewDockerVMRpcClient(conn).DockerVMCommunicate(context.Background())
}
// newRuntimeConn create rpc connection
func newRuntimeConn() (protogo.DockerVMRpc_DockerVMCommunicateClient, error) {
var conn *grpc.ClientConn
var err error
dialOpts := []grpc.DialOption{
grpc.WithInsecure(),
grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(config.RuntimeClient.MaxRecvMsgSize),
grpc.MaxCallSendMsgSize(config.RuntimeClient.MaxSendMsgSize),
),
grpc.WithWriteBufferSize(4 * 1024 * 1024),
grpc.WithReadBufferSize(4 * 1024 * 1024),
grpc.WithInitialWindowSize(64 * 1024 * 1024),
grpc.WithInitialConnWindowSize(64 * 1024 * 1024),
}
if config.RuntimeClient.RuntimeRPCProtocolType == TCP {
url := fmt.Sprintf("%s:%s", config.RuntimeClient.RuntimeHost, config.RuntimeClient.RuntimePort)
conn, err = grpc.Dial(url, dialOpts...)
if err != nil {
return nil, err
}
} else {
dialOpts = append(
dialOpts,
grpc.WithContextDialer(
func(ctx context.Context, sock string) (net.Conn, error) {
unixAddress, _ := net.ResolveUnixAddr("unix", sock)
conn, err := net.DialUnix("unix", nil, unixAddress)
return conn, err
},
),
)
conn, err = grpc.DialContext(context.Background(), config.RuntimeClient.RuntimeUDSSockPath, dialOpts...)
if err != nil {
return nil, err
}
}
return protogo.NewDockerVMRpcClient(conn).DockerVMCommunicate(context.Background())
}
// GetClientStream get rpc stream
func GetClientStream(conn *grpc.ClientConn) (protogo.DockerVMRpc_DockerVMCommunicateClient, error) {
return protogo.NewDockerVMRpcClient(conn).DockerVMCommunicate(context.Background())
}
/*
Copyright (C) BABEC. All rights reserved.
Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
SPDX-License-Identifier: Apache-2.0
*/
package sandbox
import (
"errors"
"fmt"
"sync"
"time"
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
"go.uber.org/zap"
)
type state string
const (
created state = "created"
ready state = "ready"
)
type ContractEngineClient struct {
logger *zap.SugaredLogger
serialLock sync.Mutex
rpcClient protogo.DockerVMRpc_DockerVMCommunicateClient
state state
putTxReqMsgFunc func(msg *protogo.DockerVMMessage, signalNotify func(signal *protogo.DockerVMMessage))
txFinishMsgChan chan *protogo.DockerVMMessage
processName string
contractName string
}
func newContractEngineClient(rpcClient protogo.DockerVMRpc_DockerVMCommunicateClient, processName, contractName string, logger *zap.SugaredLogger) *ContractEngineClient {
return &ContractEngineClient{
logger: logger,
serialLock: sync.Mutex{},
rpcClient: rpcClient,
txFinishMsgChan: make(chan *protogo.DockerVMMessage, 200),
state: created,
processName: processName,
contractName: contractName,
}
}
func (c *ContractEngineClient) Start() error {
c.logger.Debugf("start contract engine client")
defer func() {
err := c.rpcClient.CloseSend()
if err != nil {
return
}
}()
// chat with engine
if err := c.chatWithEngine(); err != nil {
return err
}
errCh := make(chan error, 1)
// listen incoming message
go func() {
if err := c.listenTxRequest(); err != nil {
errCh <- err
}
}()
// send signal
go func() {
if err := c.sendTxFinishMsg(); err != nil {
errCh <- err
}
}()
return <-errCh
}
func (c *ContractEngineClient) chatWithEngine() error {
c.logger.Debugf("sandbox - chat with manager")
// Send the register
if err := c.sendMessage(
&protogo.DockerVMMessage{
Type: protogo.DockerVMType_REGISTER,
CrossContext: &protogo.CrossContext{
ProcessName: c.processName,
},
},
); err != nil {
return fmt.Errorf("error sending chaincode REGISTER: %s", err)
}
c.state = ready
return nil
}
// listenTxRequest listen request from contract engine
func (c *ContractEngineClient) listenTxRequest() error {
c.logger.Debugf("start receiving engine server message")
// holds return values from gRPC Recv below
// recv message
for {
msg, err := c.rpcClient.Recv()
switch {
case err != nil:
err := fmt.Errorf("client receive error from contract engine: %s", err)
return err
case msg == nil:
err := errors.New("received nil message, ending chaincode stream")
return err
default:
c.logger.Debugf("[%s] sandbox receive txRequest from contract engine, msgType [%s]", msg.TxId, msg.Type)
EnterNextStep(msg, protogo.StepType_SANDBOX_GRPC_RECEIVE_TX_REQUEST, "")
c.putTxReqMsgFunc(msg, c.PutFinishMsg)
}
}
}
// RegisterTxRequestPutFunc register put func to send txRequest to txHandler with a callback fun that returns a finish signal
func (c *ContractEngineClient) RegisterTxRequestPutFunc(txRequestPutFunc func(msg *protogo.DockerVMMessage,
txFinishMsgNotifyFunc func(signal *protogo.DockerVMMessage))) {
c.putTxReqMsgFunc = txRequestPutFunc
}
func (c *ContractEngineClient) PutFinishMsg(msg *protogo.DockerVMMessage) {
c.logger.Debugf("put finish signal to signal queue, txId [%s], msgType [%s], chan len: [%d]", msg.TxId,
msg.Type, len(c.txFinishMsgChan))
c.txFinishMsgChan <- msg
}
// sendTxFinishMsg send message to contract engine
func (c *ContractEngineClient) sendTxFinishMsg() error {
c.logger.Debugf("start sending signal to contract engine server")
for msg := range c.txFinishMsgChan {
c.logger.Debugf("get msg from signal queue, txId: [%s], msgType: [%s]", msg.TxId, msg.Type)
timeByte, _ := time.Now().MarshalBinary()
msg.Response = &protogo.TxResponse{
Result: timeByte,
}
if err := c.sendMessage(msg); err != nil {
c.logger.Errorf("send finish message to engine failed, err:%s", err)
return err
}
}
return nil
}
// sendMessage Send on the gRPC client.
func (c *ContractEngineClient) sendMessage(msg *protogo.DockerVMMessage) error {
c.serialLock.Lock()
defer c.serialLock.Unlock()
c.logger.Debugf("[%s] sandbox send signal to contract engine, msg: [%+v]", msg.TxId, msg)
return c.rpcClient.Send(msg)
}
......@@ -5,10 +5,11 @@ Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
SPDX-License-Identifier: Apache-2.0
*/
package logger
package sandbox
import (
"os"
"strings"
"time"
"go.uber.org/zap"
......@@ -16,30 +17,27 @@ import (
)
const (
SHOWLINE = false
LEVEL_DEBUG = "DEBUG"
LEVEL_INFO = "INFO"
LEVEL_WARN = "WARN"
LEVEL_ERROR = "ERROR"
SHOWLINE = false
LEVEL_DEBUG = "DEBUG"
LEVEL_INFO = "INFO"
LEVEL_WARN = "WARN"
LEVEL_ERROR = "ERROR"
MODULE_SANDBOX = "Sandbox"
MODULE_CONTRACT = "Contract"
)
func NewDockerLogger(name, level string) *zap.SugaredLogger {
var (
contractLoggerModule string
)
func newDockerLogger(name, level string) *zap.SugaredLogger {
encoder := getEncoder()
writeSyncer := getLogWriter()
var logLevel zapcore.Level
switch level {
case LEVEL_DEBUG:
logLevel = zap.DebugLevel
case LEVEL_INFO:
logLevel = zap.InfoLevel
case LEVEL_WARN:
logLevel = zap.WarnLevel
case LEVEL_ERROR:
logLevel = zap.ErrorLevel
default:
logLevel = zap.InfoLevel
// default log level is info
logLevel := new(zapcore.Level)
if err := logLevel.UnmarshalText([]byte(level)); err != nil {
panic("unknown log level, logLevelFromConfig: " + level + "," + err.Error())
}
core := zapcore.NewCore(
......@@ -99,3 +97,18 @@ func CustomLevelEncoder(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder)
func CustomTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(t.Format("2006-01-02 15:04:05.000"))
}
func generateLoggerModuleName(iterms ...string) string {
itermLen := len(iterms)
var sb strings.Builder
sb.WriteString("[")
for index, iterm := range iterms {
sb.WriteString(iterm)
if index+1 < itermLen {
sb.WriteString(" ")
}
}
sb.WriteString("]")
return sb.String()
}
/*
Copyright (C) BABEC. All rights reserved.
Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
SPDX-License-Identifier: Apache-2.0
*/
package sandbox
import (
"errors"
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
"go.uber.org/zap"
)
type RuntimeClient struct {
logger *zap.SugaredLogger
rpcClient protogo.DockerVMRpc_DockerVMCommunicateClient
contractName string
txId string
responseNotify func(msg *protogo.DockerVMMessage)
sendMsgCh chan *protogo.DockerVMMessage
stopReceive chan struct{}
stopSend chan struct{}
}
func newRuntimeClient(rpcClient protogo.DockerVMRpc_DockerVMCommunicateClient, contractName string, logger *zap.SugaredLogger) *RuntimeClient {
return &RuntimeClient{
logger: logger,
rpcClient: rpcClient,
contractName: contractName,
sendMsgCh: make(chan *protogo.DockerVMMessage, 1),
}
}
func (r *RuntimeClient) Start() error {
r.logger.Debugf("start runtime client")
defer func() {
err := r.rpcClient.CloseSend()
if err != nil {
return
}
}()
errCh := make(chan error, 1)
go func() {
if err := r.recvRoutine(); err != nil {
errCh <- err
}
}()
go func() {
if err := r.sendRoutine(); err != nil {
errCh <- err
}
}()
return <-errCh
}
func (r *RuntimeClient) recvRoutine() error {
r.logger.Debugf("start receiving runtime server message")
for {
select {
case <-r.stopReceive:
r.logger.Debugf("close runtime client receive goroutine")
return errors.New("close runtime client receive goroutine")
default:
receivedMsg, recvErr := r.rpcClient.Recv()
if recvErr != nil {
r.logger.Errorf("client receive err from runtime %s", recvErr)
close(r.stopSend)
}
r.logger.Debugf("[%s] receive msg from runtime server, msg type [%s]", receivedMsg.TxId, receivedMsg.Type)
switch receivedMsg.Type {
case protogo.DockerVMType_GET_STATE_RESPONSE,
protogo.DockerVMType_GET_BATCH_STATE_RESPONSE,
protogo.DockerVMType_CREATE_KV_ITERATOR_RESPONSE,
protogo.DockerVMType_CONSUME_KV_ITERATOR_RESPONSE,
protogo.DockerVMType_CREATE_KEY_HISTORY_TER_RESPONSE,
protogo.DockerVMType_CONSUME_KEY_HISTORY_ITER_RESPONSE,
protogo.DockerVMType_GET_SENDER_ADDRESS_RESPONSE,
protogo.DockerVMType_CALL_CONTRACT_RESPONSE:
if r.responseNotify == nil {
r.logger.Errorf("[%s] failed to handle resposne, sys_call responseNotify is nil", receivedMsg.TxId)
continue
}
if err := currentTxDuration.EndSysCall(receivedMsg); err != nil {
r.logger.Warnf("failed to end syscall, %v", err)
}
r.responseNotify(receivedMsg)
default:
r.logger.Errorf("unknown message type, received msg: [%v]", receivedMsg)
}
}
}
}
func (r *RuntimeClient) sendRoutine() error {
r.logger.Debugf("start sending sys_call message")
for msg := range r.sendMsgCh {
if msg.Type != protogo.DockerVMType_TX_RESPONSE {
currentTxDuration.StartSysCall(msg)
}
r.logger.Debugf("get msg from runtime client sendMsgCh, txId: [%s], msgType: [%s]", msg.TxId, msg.Type)
//EnterNextStep(msg, protogo.StepType_SANDBOX_GRPC_SEND_CHAIN_RESP)
if err := r.sendMessage(msg); err != nil {
r.logger.Errorf("send msg to runtime failed, err:%s", err)
return err
}
}
r.logger.Errorf("send routine exit")
return nil
}
// PutMsgWithNotify put msg nad register call back func for sys_call response
func (r *RuntimeClient) PutMsgWithNotify(msg *protogo.DockerVMMessage,
syscallResponseNotifyFunc func(msg *protogo.DockerVMMessage)) {
r.RegisterResponseNotifier(syscallResponseNotifyFunc)
r.PutMsg(msg)
}
// PutMsg put msg to send channel
func (r *RuntimeClient) PutMsg(msg *protogo.DockerVMMessage) {
r.logger.Debugf("put msg to sendMsgCh, txId [%s], msgType [%s], chan len: [%d]",
msg.TxId, msg.Type, len(r.sendMsgCh))
r.sendMsgCh <- msg
}
// RegisterResponseNotifier register callback func for sys_call response
func (r *RuntimeClient) RegisterResponseNotifier(syscallResponseNotifyFunc func(msg *protogo.DockerVMMessage)) {
r.responseNotify = syscallResponseNotifyFunc
}
func (r *RuntimeClient) sendMessage(msg *protogo.DockerVMMessage) error {
r.logger.Debugf("[%s] sandbox send msg to runtime server, msg: [%+v]", msg.TxId, msg)
return r.rpcClient.Send(msg)
}
/*
Copyright (C) BABEC. All rights reserved.
Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
SPDX-License-Identifier: Apache-2.0
*/
package sandbox
import (
"os"
"os/signal"
"syscall"
"time"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sdk"
)
const (
version = "Contract_SDK_Version:fc5101a7f55d71e234242163fd1bdfaa4fdea7437bf161f7e1cf7c49e57580a2"
ExitCode_UNKNOWN = 1
ExitCode_SIGINT = 128 + 2
ExitCode_SIGTERM = 128 + 15
)
func Start(contract sdk.Contract) error {
args := os.Args
if err := initConfig(); err != nil {
return err
}
contractLoggerModule = generateLoggerModuleName(MODULE_CONTRACT, config.ProcessName)
logger := newDockerLogger(generateLoggerModuleName(MODULE_SANDBOX, config.ProcessName), config.LogLevel)
logger.Debugf("loglevel: %s", args[4])
logger.Debug(version)
// engine client
engineRPCClient, err := newUDSClient()
if err != nil {
logger.Errorf("new engine client failed, err: %s", err.Error())
return err
}
engineClient := newContractEngineClient(engineRPCClient, config.ProcessName, config.ContractName, logger)
runtimeRPCClient, err := newRuntimeConn()
if err != nil {
logger.Errorf("new runtime client failed, err: %s", err.Error())
return err
}
runtimeClient := newRuntimeClient(runtimeRPCClient, config.ContractName, logger)
txHandler := newTxHandler(contract, config.ProcessName, config.ContractName, logger)
// Register
txHandler.RegisterSyscallMsgSendFunc(runtimeClient.PutMsgWithNotify)
engineClient.RegisterTxRequestPutFunc(txHandler.PutMsgWithNotify)
errCh := make(chan error, 1)
go func() {
errCh <- txHandler.Start()
}()
go func() {
errCh <- runtimeClient.Start()
}()
go func() {
errCh <- engineClient.Start()
}()
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
logger.Infof("runtime client started, contract engine client started, tx handler started, all is well!")
select {
case err = <-errCh:
logger.Errorf("sandbox stop with error, err: %s", err.Error())
case sig := <-sigs:
switch sig {
case syscall.SIGTERM:
logger.Debugf("receive signal [%d:%s], exit normally", sig, sig.String())
logger.Debug("sandbox - end")
os.Exit(ExitCode_SIGTERM)
case syscall.SIGINT:
// print tx duration and stack
logger.Infof("receive signal [%d:%s]", sig, sig.String())
logger.Infof("syscall statistics of current tx %s, start time: %v, end time: %v, current status: %v, syscalls: %s, steps: %s",
currentTxDuration.Tx.TxId, time.Unix(0, currentTxDuration.StartTime), time.Unix(0, currentTxDuration.EndTime),
currentStatus, currentTxDuration.PrintSysCallList(), PrintTxSteps(currentTxDuration.Tx))
logger.Infof("stack info: %s", GetAllStackMsg())
logger.Debug("sandbox - end")
os.Exit(ExitCode_SIGINT)
default:
logger.Infof("receive signal [%d:%s] from unknown source", sig, sig.String())
logger.Debug("sandbox - end")
os.Exit(ExitCode_UNKNOWN)
}
}
logger.Debug("sandbox - end")
return err
}
/*
Copyright (C) BABEC. All rights reserved.
Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
SPDX-License-Identifier: Apache-2.0
*/
package sandbox
import (
"errors"
"fmt"
"strings"
"time"
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
)
var (
currentTxDuration = TxDuration{
SysCallList: make([]*SysCallDuration, 0),
}
currentStatus = BeforeListening
)
type TxStatus string
const (
BeforeListening TxStatus = "before listening"
BeforeReceive TxStatus = "before receive"
BeforeExecute TxStatus = "before execute"
Executing TxStatus = "executing"
WaitingSysCallResponse TxStatus = "waiting syscall response"
AfterExecuted TxStatus = "after executed"
AfterSendResponse TxStatus = "after send response"
Finished TxStatus = "finished"
)
type SysCallDuration struct {
OpType protogo.DockerVMType
StartTime int64
TotalDuration int64
}
func (s *SysCallDuration) ToString() string {
return fmt.Sprintf("%s start: %v, spend: %dμs; ",
s.OpType.String(), time.Unix(s.StartTime/1e9, s.StartTime%1e9), s.TotalDuration/1000,
)
}
type TxDuration struct {
Tx *protogo.DockerVMMessage
StartTime int64
EndTime int64
TotalDuration int64
SysCallCnt int32
SysCallDuration int64
CrossCallCnt int32
CrossCallDuration int64
SysCallList []*SysCallDuration
}
func NewTxDuration(tx *protogo.DockerVMMessage, startTime int64) *TxDuration {
return &TxDuration{
Tx: tx,
StartTime: startTime,
}
}
func (t *TxDuration) Reset(tx *protogo.DockerVMMessage, startTime int64) {
t.Tx = tx
t.StartTime = startTime
t.EndTime = t.StartTime
t.TotalDuration = 0
t.SysCallCnt = 0
t.SysCallDuration = 0
t.CrossCallCnt = 0
t.CrossCallDuration = 0
t.SysCallList = t.SysCallList[:0]
}
func (t *TxDuration) ToString() string {
return fmt.Sprintf("%s spend time: %dμs, syscall: %dμs(%d), cross contract: %dμs(%d)",
t.Tx.TxId, t.TotalDuration/1000,
t.SysCallDuration/1000, t.SysCallCnt,
t.CrossCallDuration/1000, t.CrossCallCnt,
)
}
func (t *TxDuration) PrintSysCallList() string {
if len(t.SysCallList) == 0 {
return "no syscalls"
}
var sb strings.Builder
for _, sysCallTime := range t.SysCallList {
sb.WriteString(sysCallTime.ToString())
}
return sb.String()
}
// StartSysCall start new sys call
func (t *TxDuration) StartSysCall(msg *protogo.DockerVMMessage) {
currentStatus = WaitingSysCallResponse
duration := &SysCallDuration{
OpType: msg.Type,
StartTime: time.Now().UnixNano(),
}
t.SysCallList = append(t.SysCallList, duration)
}
// EndSysCall close new sys call
func (t *TxDuration) EndSysCall(msg *protogo.DockerVMMessage) error {
currentStatus = Executing
latestSysCall, err := t.GetLatestSysCall()
if err != nil {
return fmt.Errorf("failed to get latest sys call, %v", err)
}
latestSysCall.TotalDuration = time.Since(time.Unix(0, latestSysCall.StartTime)).Nanoseconds()
t.addSysCallDuration(latestSysCall)
return nil
}
// GetLatestSysCall returns latest sys call
func (t *TxDuration) GetLatestSysCall() (*SysCallDuration, error) {
if len(t.SysCallList) == 0 {
return nil, errors.New("sys call list length == 0")
}
return t.SysCallList[len(t.SysCallList)-1], nil
}
// addSysCallDuration add the count of system calls and the duration of system calls to the total record
func (t *TxDuration) addSysCallDuration(duration *SysCallDuration) {
if duration == nil {
return
}
switch duration.OpType {
case protogo.DockerVMType_GET_BYTECODE_REQUEST:
case protogo.DockerVMType_GET_STATE_REQUEST, protogo.DockerVMType_GET_BATCH_STATE_REQUEST,
protogo.DockerVMType_CREATE_KV_ITERATOR_REQUEST, protogo.DockerVMType_CONSUME_KV_ITERATOR_REQUEST,
protogo.DockerVMType_CREATE_KEY_HISTORY_ITER_REQUEST, protogo.DockerVMType_CONSUME_KEY_HISTORY_ITER_REQUEST,
protogo.DockerVMType_GET_SENDER_ADDRESS_REQUEST:
// record all syscalls except cross contract calls and txResponse
t.SysCallCnt++
t.SysCallDuration += duration.TotalDuration
case protogo.DockerVMType_CALL_CONTRACT_REQUEST:
// cross contract calls are recorded separately, which is different from syscall
t.CrossCallCnt++
t.CrossCallDuration += duration.TotalDuration
default:
return
}
}
// EnterNextStep enter next duration tx step
func EnterNextStep(msg *protogo.DockerVMMessage, stepType protogo.StepType, log string) {
if config.DisableSlowLog {
return
}
if stepType != protogo.StepType_RUNTIME_PREPARE_TX_REQUEST {
endTxStep(msg)
}
addTxStep(msg, stepType, log)
if stepType == protogo.StepType_RUNTIME_HANDLE_TX_RESPONSE {
endTxStep(msg)
}
}
func addTxStep(msg *protogo.DockerVMMessage, stepType protogo.StepType, log string) {
stepDur := &protogo.StepDuration{
Type: stepType,
StartTime: time.Now().UnixNano(),
Msg: log,
}
msg.StepDurations = append(msg.StepDurations, stepDur)
}
func endTxStep(msg *protogo.DockerVMMessage) {
if len(msg.StepDurations) == 0 {
return
}
stepLen := len(msg.StepDurations)
currStep := msg.StepDurations[stepLen-1]
firstStep := msg.StepDurations[0]
currStep.UntilDuration = time.Since(time.Unix(0, firstStep.StartTime)).Nanoseconds()
currStep.StepDuration = time.Since(time.Unix(0, currStep.StartTime)).Nanoseconds()
}
// PrintTxSteps print all duration tx steps
func PrintTxSteps(msg *protogo.DockerVMMessage) string {
var sb strings.Builder
for _, step := range msg.StepDurations {
sb.WriteString(fmt.Sprintf("<step: %q, start time: %v, step cost: %vms, until cost: %vms, msg: %s> ",
step.Type, time.Unix(0, step.StartTime),
time.Duration(step.StepDuration).Seconds()*1000,
time.Duration(step.UntilDuration).Seconds()*1000,
step.Msg))
}
return sb.String()
}
// PrintTxStepsWithTime print all duration tx steps with time limt
func PrintTxStepsWithTime(msg *protogo.DockerVMMessage, untilDuration time.Duration) (string, bool) {
if len(msg.StepDurations) == 0 {
return "", false
}
lastStep := msg.StepDurations[len(msg.StepDurations)-1]
var sb strings.Builder
if lastStep.UntilDuration > untilDuration.Nanoseconds() {
sb.WriteString("slow tx overall: ")
sb.WriteString(PrintTxSteps(msg))
return sb.String(), true
}
for _, step := range msg.StepDurations {
if step.StepDuration > time.Millisecond.Nanoseconds()*500 {
sb.WriteString(fmt.Sprintf("slow tx at step %q, step cost: %vms: ",
step.Type, time.Duration(step.StepDuration).Seconds()*1000))
sb.WriteString(PrintTxSteps(msg))
return sb.String(), true
}
}
return "", false
}
/*
Copyright (C) BABEC. All rights reserved.
Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
SPDX-License-Identifier: Apache-2.0
*/
package sandbox
import (
"strings"
"time"
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
"chainmaker.org/chainmaker/contract-sdk-go/v2/sdk"
"go.uber.org/zap"
)
const (
_dockerGoMethodInitContract = "InitContract"
_dockerGoMethodUpgradeContract = "UpgradeContract"
_initContract = "init_contract"
_upgradeContract = "upgrade"
_invokeContract = "invoke_contract" //Compatible with version < 2.3.0
)
type TxHandler struct {
sandboxLogger *zap.SugaredLogger
contractLogger *zap.SugaredLogger
contract sdk.Contract
contractName string
processName string
txId string
originalTxId string
crossCtx *protogo.CrossContext
chainId string
sendSyscallMsg func(msg *protogo.DockerVMMessage, responseNotify func(msg *protogo.DockerVMMessage))
txFinishMsgNotifyFunc func(signal *protogo.DockerVMMessage)
pendingQueue chan *protogo.DockerVMMessage
}
func newTxHandler(contract sdk.Contract, processName, contractName string, logger *zap.SugaredLogger) *TxHandler {
return &TxHandler{
sandboxLogger: logger,
contractLogger: newDockerLogger(contractLoggerModule, config.LogLevel),
contract: contract,
contractName: contractName,
processName: processName,
pendingQueue: make(chan *protogo.DockerVMMessage, 200),
}
}
// PutMsg put txRequest to pendingQueue
func (h *TxHandler) PutMsg(msg *protogo.DockerVMMessage) {
h.sandboxLogger.Debugf("put txRequest to pending queue, txTd [%s], txType [%s]", msg.TxId, msg.Type)
//EnterNextStep(msg, protogo.StepType_SANDBOX_GRPC_SEND_TX_REQUEST, "")
h.pendingQueue <- msg
}
// RegisterTxFinishMsgNotifyFunc register func to send tx finish msg to engine
func (h *TxHandler) RegisterTxFinishMsgNotifyFunc(txFinishMsgNotifyFunc func(msg *protogo.DockerVMMessage)) {
h.txFinishMsgNotifyFunc = txFinishMsgNotifyFunc
}
// PutMsgWithNotify put tx request to handler and register finish signal callback func
func (h *TxHandler) PutMsgWithNotify(msg *protogo.DockerVMMessage,
txFinishMsgNotifyFunc func(msg *protogo.DockerVMMessage)) {
h.RegisterTxFinishMsgNotifyFunc(txFinishMsgNotifyFunc)
h.PutMsg(msg)
}
// RegisterSyscallMsgSendFunc register runtime client syscall func with call back func
func (h *TxHandler) RegisterSyscallMsgSendFunc(f func(msg *protogo.DockerVMMessage,
syscallResponseNotifyFunc func(msg *protogo.DockerVMMessage))) {
h.sendSyscallMsg = f
}
func (h *TxHandler) sendResponse(resp *protogo.DockerVMMessage) {
h.sendSyscallMsg(resp, nil)
}
func (h *TxHandler) Start() error {
h.sandboxLogger.Debugf("start listen pending queue")
return h.listenPendingQueue()
}
func (h *TxHandler) listenPendingQueue() error {
currentStatus = BeforeReceive
errCh := make(chan error)
for {
select {
case msg := <-h.pendingQueue:
h.sandboxLogger.Debugf("get msg from pending queue, txId: [%s], msgType: [%s]", msg.TxId, msg.Type)
if err := h.handleTxRequest(msg); err != nil {
errCh <- err
}
case err := <-errCh:
return err
}
}
}
func getOriginalTxId(txId string) string {
return strings.Split(txId, "#")[0]
}
func (h *TxHandler) handleTxRequest(msg *protogo.DockerVMMessage) error {
h.chainId = msg.ChainId
h.txId = msg.TxId
h.originalTxId = getOriginalTxId(h.txId)
h.crossCtx = msg.CrossContext
h.crossCtx.ProcessName = h.processName
// init time statistics
startTime := time.Now()
currentTxDuration.Reset(msg, startTime.UnixNano())
//EnterNextStep(msg, protogo.StepType_SANDBOX_HANDLER_RECEIVE_TX_REQUEST, "")
currentStatus = BeforeExecute
defer func() {
currentTxDuration.TotalDuration = time.Since(startTime).Nanoseconds()
h.sandboxLogger.Debugf(currentTxDuration.ToString())
}()
args := msg.GetRequest().GetParameters()
s := sdk.NewSDK(
h.crossCtx,
h.sendSyscallMsg,
h.txId,
h.originalTxId,
h.chainId,
h.contractName,
h.contractLogger,
h.sandboxLogger,
args,
)
sdk.Instance = s
method := msg.Request.Method
// compatible with version < 2.3.0 (method in parameters)
if method == _invokeContract {
if methodByte, ok := msg.Request.Parameters["method"]; ok {
// found method, replace 'invoke_contract' method to real method
method = string(methodByte)
}
}
currentStatus = Executing
var response protogo.Response
switch method {
case _initContract:
response = h.contract.InitContract()
case _upgradeContract:
response = h.contract.UpgradeContract()
default:
response = h.contract.InvokeContract(method)
}
// construct complete message
writeMap := s.GetWriteMap()
readMap := s.GetReadMap()
events := s.GetEvents()
txResponse := &protogo.TxResponse{
TxId: h.txId,
ChainId: h.chainId,
}
signal := &protogo.DockerVMMessage{
ChainId: h.chainId,
TxId: msg.TxId,
CrossContext: h.crossCtx,
Type: protogo.DockerVMType_COMPLETED,
SysCallMessage: nil,
Request: nil,
Response: nil,
}
if response.Status == 0 {
txResponse.Code = protogo.DockerVMCode_OK
txResponse.Result = response.Payload
txResponse.Message = "Success"
txResponse.WriteMap = writeMap
txResponse.ReadMap = readMap
var responseEvents []*protogo.DockerContractEvent
for _, event := range events {
responseEvents = append(responseEvents, &protogo.DockerContractEvent{
Topic: event.Topic,
ContractName: event.ContractName,
Data: event.Data,
})
}
txResponse.Events = responseEvents
} else {
txResponse.Code = protogo.DockerVMCode_FAIL
txResponse.Result = []byte(response.Message)
txResponse.Message = "Fail"
txResponse.WriteMap = nil
txResponse.ReadMap = nil
txResponse.Events = nil
if method == _dockerGoMethodInitContract || method == _dockerGoMethodUpgradeContract {
signal.Type = protogo.DockerVMType_ERROR
}
}
respMsg := &protogo.DockerVMMessage{
ChainId: h.chainId,
TxId: h.txId,
Type: protogo.DockerVMType_TX_RESPONSE,
Response: txResponse,
Request: nil,
SysCallMessage: nil,
}
currentStatus = AfterExecuted
EnterNextStep(msg, protogo.StepType_SANDBOX_HANDLER_EXECUTE, "")
respMsg.StepDurations = msg.StepDurations
h.sendResponse(respMsg)
currentStatus = AfterSendResponse
signal.StepDurations = msg.StepDurations
// 发送finish信号
h.txFinishMsgNotifyFunc(signal)
currentStatus = Finished
currentTxDuration.EndTime = time.Now().UnixNano()
return nil
}
/*
Copyright (C) BABEC. All rights reserved.
Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
SPDX-License-Identifier: Apache-2.0
*/
package sandbox
import (
"runtime"
)
const (
stackBufferSize = 1048576
)
func GetAllStackMsg() string {
var buf [stackBufferSize]byte
n := runtime.Stack(buf[:], true)
return string(buf[:n])
}
/*
Copyright (C) BABEC. All rights reserved.
Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
SPDX-License-Identifier: Apache-2.0
*/
package sdk
const (
KeyRegisterProcessName = "KEY_REGISTER_PROCESS_NAME"
KeySenderAddr = "KEY_SENDER_ADDR"
KeyCallContractResp = "KEY_CALL_CONTRACT_RESPONSE"
KeyCallContractReq = "KEY_CALL_CONTRACT_REQUEST"
KeyStateKey = "KEY_STATE_KEY"
KeyUserKey = "KEY_USER_KEY"
KeyUserField = "KEY_USER_FIELD"
KeyStateValue = "KEY_STATE_VALUE"
KeyKVIterKey = "KEY_KV_ITERATOR_KEY"
KeyIterIndex = "KEY_KV_ITERATOR_INDEX"
KeyHistoryIterKey = "KEY_HISTORY_ITERATOR_KEY"
KeyHistoryIterField = "KEY_HISTORY_ITERATOR_FIELD"
//KeyHistoryIterIndex = "KEY_HISTORY_ITERATOR_INDEX"
KeyContractName = "KEY_CONTRACT_NAME"
KeyIteratorFuncName = "KEY_ITERATOR_FUNC_NAME"
KeyIterStartKey = "KEY_ITERATOR_START_KEY"
KeyIterStartField = "KEY_ITERATOR_START_FIELD"
KeyIterLimitKey = "KEY_ITERATOR_LIMIT_KEY"
KeyIterLimitField = "KEY_ITERATOR_LIMIT_FIELD"
KeyWriteMap = "KEY_WRITE_MAP"
KeyIteratorHasNext = "KEY_ITERATOR_HAS_NEXT"
KeyTxId = "KEY_TX_ID"
KeyBlockHeight = "KEY_BLOCK_HEIGHT"
KeyIsDelete = "KEY_IS_DELETE"
KeyTimestamp = "KEY_TIMESTAMP"
)
const (
MapSize = 8
// common easyCodec key
EC_KEY_TYPE_KEY ECKeyType = "key"
EC_KEY_TYPE_FIELD ECKeyType = "field"
EC_KEY_TYPE_VALUE ECKeyType = "value"
EC_KEY_TYPE_TX_ID ECKeyType = "txId"
EC_KEY_TYPE_BLOCK_HEITHT ECKeyType = "blockHeight"
EC_KEY_TYPE_IS_DELETE ECKeyType = "isDelete"
EC_KEY_TYPE_TIMESTAMP ECKeyType = "timestamp"
// stateKvIterator method
FuncKvIteratorCreate = "createKvIterator"
FuncKvPreIteratorCreate = "createKvPreIterator"
FuncKvIteratorHasNext = "kvIteratorHasNext"
FuncKvIteratorNext = "kvIteratorNext"
FuncKvIteratorClose = "kvIteratorClose"
// keyHistoryKvIterator method
FuncKeyHistoryIterHasNext = "keyHistoryIterHasNext"
FuncKeyHistoryIterNext = "keyHistoryIterNext"
FuncKeyHistoryIterClose = "keyHistoryIterClose"
// int32 representation of bool
BoolTrue Bool = 1
BoolFalse Bool = 0
sandboxKVStoreSeparator = "#"
// default batch keys count limit
defaultLimitKeys = 10000
)
......@@ -4,7 +4,7 @@ Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
SPDX-License-Identifier: Apache-2.0
*/
package shim
package sdk
import (
"chainmaker.org/chainmaker/common/v2/crypto"
......
......@@ -5,17 +5,19 @@ Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
SPDX-License-Identifier: Apache-2.0
*/
package shim
package sdk
import "chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
import (
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
)
const (
// OK constant - status code less than 400, endorser will endorse it.
// OK means init or invoke successfully.
OK = 200
OK = 0
// ERROR constant - default error value
ERROR = 500
ERROR = 1
)
// Success ...
......
This diff is collapsed.
......@@ -5,7 +5,7 @@ Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
SPDX-License-Identifier: Apache-2.0
*/
package shim
package sdk
import (
"chainmaker.org/chainmaker/common/v2/serialize"
......@@ -13,15 +13,19 @@ import (
vmPb "chainmaker.org/chainmaker/pb-go/v2/vm"
)
// CMContract user contract interface
type CMContract interface {
// Contract user contract common
type Contract interface {
// InitContract used to deploy and upgrade contract
InitContract(stub CMStubInterface) protogo.Response
// InvokeContract used to invoke contract
InvokeContract(stub CMStubInterface) protogo.Response
InitContract() protogo.Response
// UpgradeContract used to upgrade contract
UpgradeContract() protogo.Response
// InvokeContract used to invoke user contract
InvokeContract(method string) protogo.Response
}
type CMStubInterface interface {
var Instance SDKInterface
type SDKInterface interface {
// GetArgs get arg from transaction parameters
// @return: 参数map
GetArgs() map[string][]byte
......@@ -31,6 +35,11 @@ type CMStubInterface interface {
// @return1: 获取结果,格式为string
// @return2: 获取错误信息
GetState(key, field string) (string, error)
// GetBatchState get [BatchKeys] from chain and db
// @param batchKey: 获取的参数名
// @return1: 获取结果
// @return2: 获取错误信息
GetBatchState(batchKeys []*vmPb.BatchKey) ([]*vmPb.BatchKey, error)
// GetStateByte get [key, field] from chain and db
// @param key: 获取的参数名
// @param field: 获取的参数名
......@@ -47,11 +56,6 @@ type CMStubInterface interface {
// @return1: 获取结果,格式为[]byte
// @return2: 获取错误信息
GetStateFromKeyByte(key string) ([]byte, error)
// GetBatchState get [BatchKeys] from chain and db
// @param batchKey: 获取的参数名
// @return1: 获取结果
// @return2: 获取错误信息
GetBatchState(batchKeys []*vmPb.BatchKey) ([]*vmPb.BatchKey, error)
// PutState put [key, field, value] to chain
// @param1 key: 参数名
// @param1 field: 参数名
......@@ -115,6 +119,9 @@ type CMStubInterface interface {
// @return1: 交易ID
// @return2: 获取错误信息
GetTxId() (string, error)
// GetTxInfo get tx info
// @param txId :合约交易ID
GetTxInfo(txId string) protogo.Response
// GetTxTimeStamp get tx timestamp
// @return1: 交易timestamp
// @return2: 获取错误信息
......@@ -143,16 +150,12 @@ type CMStubInterface interface {
// @param format: 日志格式化模板
// @param a: 模板参数
Errorf(format string, a ...interface{})
// Fatalf record log to chain server
// @param format: 日志格式化模板
// @param a: 模板参数
Fatalf(format string, a ...interface{})
// CallContract invoke another contract and get response
// @param1: 合约名称
// @param2: 合约版本
// @param3: 合约参数
// @param2: 合约方法
// @param3: 合约合约参数
// @return1: 合约结果
CallContract(contractName, contractVersion string, args map[string][]byte) protogo.Response
CallContract(contractName, method string, args map[string][]byte) protogo.Response
// NewIterator range of [startKey, limitKey), front closed back open
// @param1: 范围查询起始key
// @param2: 范围查询结束key
......@@ -183,10 +186,20 @@ type CMStubInterface interface {
// @return1: 根据key, field 生成的历史迭代器
// @return2: 获取错误信息
NewHistoryKvIterForKey(key, field string) (KeyHistoryKvIter, error)
// GetSenderAddr Get the address of the tx sender
// @return1: 交易发起方地址
// GetSenderAddr Get the address of the origin caller address, same with Origin()
// @return1: origin caller address
// @return2: 获取错误信息
//Deprecated
GetSenderAddr() (string, error)
// Sender Get the address of the sender address, if the contract is called by another contract, the result will be
// the caller contract's address
// @return1: sender address
// @return2: 获取错误信息
Sender() (string, error)
// Origin Get the address of the tx origin caller address
// @return1: origin caller address
// @return2: 获取错误信息
Origin() (string, error)
}
// ResultSet iterator query result
......@@ -209,6 +222,16 @@ type ResultSetKV interface {
type KeyHistoryKvIter interface {
ResultSet
// Next return currentTxId, blockHeight, timestamp, value, isDelete, error
// Next return txId, blockHeight, timestamp, value, isDelete, error
Next() (*KeyModification, error)
}
type KeyModification struct {
Key string
Field string
Value []byte
TxId string
BlockHeight int
IsDelete bool
Timestamp string
}
This diff is collapsed.
This diff is collapsed.
/*
Copyright (C) BABEC. All rights reserved.
Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
SPDX-License-Identifier: Apache-2.0
*/
package internal
import (
"context"
"net"
"time"
"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
"google.golang.org/grpc"
)
const (
dialTimeout = 10 * time.Second
maxRecvMessageSize = 100 * 1024 * 1024 // 100 MiB
maxSendMessageSize = 100 * 1024 * 1024 // 100 MiB
)
// NewClientConn ...
func NewClientConn(sockAddress string) (*grpc.ClientConn, error) {
dialOpts := []grpc.DialOption{
grpc.WithInsecure(),
grpc.WithContextDialer(func(ctx context.Context, sockAddress string) (net.Conn, error) {
unixAddress, err := net.ResolveUnixAddr("unix", sockAddress)
conn, err := net.DialUnix("unix", nil, unixAddress)
return conn, err
}),
grpc.FailOnNonTempDialError(true),
grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(maxRecvMessageSize),
grpc.MaxCallSendMsgSize(maxSendMessageSize),
),
}
ctx, cancel := context.WithTimeout(context.Background(), dialTimeout)
defer cancel()
return grpc.DialContext(ctx, sockAddress, dialOpts...)
}
func NewContractClient(conn *grpc.ClientConn) (protogo.DMSRpc_DMSCommunicateClient, error) {
return protogo.NewDMSRpcClient(conn).DMSCommunicate(context.Background())
}
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