区块链学习2-合约开发
概述
智能合约本质上是运行在某种环境(例如虚拟机)中的一段代码逻辑。
长安链的智能合约是运行在长安链上的一组“动态代码”,类似于Fabric的chaincode,Fabric的智能合约称为链码(chaincode),分为系统链码和用户链码。长安链的合约分为用户合约和系统合约。
长安链·ChainMaker目前已经支持使用C++、Go、Rust、Solidity进行智能合约开发,这里介绍goland合约的开发参考。
环境依赖
长安链运行docker-go合约的环境依赖如下:
名称 | 版本 | 描述 | 是否必须 |
---|---|---|---|
docker | 18+ | 独立运行容器 | 是 |
7zip | 16+ | 压缩、解压合约文件 | 是 |
2.2.0版本的合约开发:
编写测试合约:
2.2.0的sdk 不支持 go mod 的形式 ,需要下载sdk 源码,参考其中的“demo"文件夹下的示例合约,
Files · v2.2.0 · chainmaker / contract-sdk-go · ChainMaker
以及开源文档,“5.7.3.1. 示例代码说明”
5. 智能合约开发 — chainmaker-docs v2.2.0 documentation
方法说明:
shim/interfaces.go · v2.2.0 · chainmaker / contract-sdk-go · ChainMaker
以下是根据官网编写的一份示例合约
/*
Copyright (C) BABEC. All rights reserved.
Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.SPDX-License-Identifier: Apache-2.0
*/package demoimport ("crypto/rand""encoding/json""log""math/big""strconv""fmt" // print"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo""chainmaker.org/chainmaker/contract-sdk-go/v2/shim"
)type FactContract struct {
}// 存证对象
type Fact struct {FileHash string `json:"FileHash"`FileName string `json:"FileName"`Time int32 `json:"time"`
}// 新建存证对象
func NewFact(FileHash string, FileName string, time int32) *Fact {fact := &Fact{FileHash: FileHash,FileName: FileName,Time: time,}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)case "random":return f.random()default:return shim.Error("invalid method")}}
func (f *FactContract) random() protogo.Response {// 随机数逻辑number, _ := rand.Int(rand.Reader, big.NewInt(10000000000))fmt.Println(number)number_str := fmt.Sprint(number)//number_str := strconv.Itoa(number)// 返回结果return shim.Success([]byte(number_str))
}func (f *FactContract) save(stub shim.CMStubInterface) protogo.Response {params := stub.GetArgs()// 获取参数fileHash := string(params["file_hash"])fileName := string(params["file_name"])timeStr := string(params["time"])time, err := strconv.Atoi(timeStr)if err != nil {msg := "time is [" + timeStr + "] not int"stub.Log(msg)return shim.Error(msg)}// 构建结构体fact := NewFact(fileHash, fileName, int32(time))// 序列化factBytes, _ := json.Marshal(fact)// 发送事件stub.EmitEvent("topic_vx", []string{fact.FileHash, fact.FileName})// 存储数据err = stub.PutStateByte("fact_bytes", fact.FileHash, factBytes)if err != nil {return shim.Error("fail to save fact bytes")}// 记录日志stub.Log("[save] FileHash=" + fact.FileHash)stub.Log("[save] FileName=" + fact.FileName)// 返回结果return shim.Success([]byte(fact.FileName + fact.FileHash))}func (f *FactContract) findByFileHash(stub shim.CMStubInterface) protogo.Response {// 获取参数FileHash := string(stub.GetArgs()["file_hash"])// 查询结果result, err := stub.GetStateByte("fact_bytes", FileHash)if err != nil {return shim.Error("failed to call get_state")}// 反序列化var fact Fact_ = json.Unmarshal(result, &fact)// 记录日志stub.Log("[find_by_file_hash] FileHash=" + fact.FileHash)stub.Log("[find_by_file_hash] FileName=" + fact.FileName)// 返回结果return shim.Success(result)
}func main() {err := shim.Start(new(FactContract))if err != nil {log.Fatal(err)}
}
编译合约
编译几个必要条件:
需要在linux环境下编译,如果在mac平台编译,需要把build.sh里面的go build main.go改成CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
代码入口包名必须为
main 见步骤1,2
main的固定写法:
package main // sdk代码中,有且仅有一个main()方法 func main() { // main()方法中,下面的代码为必须代码,不建议修改main()方法当中的代码// 其中,TestContract为用户实现合约的具体名称err := shim.Start(new(TestContract))if err != nil {log.Fatal(err)} }
3. 必须实现以下几个方法:
// 合约结构体,合约名称需要写入main()方法当中
type TestContract struct {
}// 合约必须实现下面两个方法:
// InitContract(stub shim.CMStubInterface) protogo.Response
// InvokeContract(stub shim.CMStubInterface) protogo.Response
// 用于合约的部署和升级
// @param stub: 合约接口
// @return: 合约返回结果,包括Success和Error
func (t *TestContract) InitContract(stub shim.CMStubInterface) protogo.Response {return shim.Success([]byte("Init Success"))
}
// 用于合约的调用
// @param stub: 合约接口
// @return: 合约返回结果,包括Success和Error
func (t *TestContract) InvokeContract(stub shim.CMStubInterface) protogo.Response {return shim.Success([]byte("Invoke Success"))
}
编译合约的具体操作步骤:
1. 将contract-sdk-go/main.go的内容替换成自己编写的合约:
2. 将自己编写的合约中package 改为main
3. 运行./build.sh 输入合约名。
2.3.0版本的合约开发:
2.3.0版本的Golang合约SDK支持通过go.mod的方式引用,可直接使用go get引用
1. 创建一个project:
2. 在terminal里执行
go get chainmaker.org/chainmaker/contract-sdk-go/v2@v2.3.2
3. 按照官方给出的示例编写合约。
2. 使用Golang进行智能合约开发 — chainmaker-docs v2.3.0 documentation
4. 在当前目录 下运行:
go build -ldflags="-s -w" -o contract_save.go
生成结果如下:
├── contract_save 生成的二进制文件
├── contract_save.7z 打包好的压缩文件,用于在链上创建合约
└── contract_save.go 源文件
部署合约到区块链中
使用长安链提供的cmc工具部署:
示例脚本:
# pk模式
./cmc client contract user create \
--contract-name=save_random \
--runtime-type=DOCKER_GO \
--byte-code-path=./testdata/docker-go-demo/save_random.7z \
--version=1.0 \
--sdk-conf-path=./testdata/sdk_config_pk.yml \
--admin-key-file-paths=./testdata/crypto-config/node1/admin/admin1/admin1.key \
--sync-result=true \
--params="{}"
# cert模式
./cmc client contract user create \
--contract-name=save_random \
--runtime-type=DOCKER_GO \
--byte-code-path=./testdata/docker-go-demo/save_random.7z \
--version=1.0 \
--sdk-conf-path=./testdata/sdk_config.yml \
--admin-key-file-paths=./testdata/crypto-config/wx-org1.chainmaker.org/user/admin1/admin1.tls.key,./testdata/crypto-config/wx-org2.chainmaker.org/user/admin1/admin1.tls.key,./testdata/crypto-config/wx-org3.chainmaker.org/user/admin1/admin1.tls.key,./testdata/crypto-config/wx-org4.chainmaker.org/user/admin1/admin1.tls.key \
--admin-crt-file-paths=./testdata/crypto-config/wx-org1.chainmaker.org/user/admin1/admin1.tls.crt,./testdata/crypto-config/wx-org2.chainmaker.org/user/admin1/admin1.tls.crt,./testdata/crypto-config/wx-org3.chainmaker.org/user/admin1/admin1.tls.crt,./testdata/crypto-config/wx-org4.chainmaker.org/user/admin1/admin1.tls.crt \
--sync-result=true \
--params="{}"
使用sdk部署:chainmaker / sdk-go · ChainMaker
示例代码参考: sdk-go/examples/user_contract_claim_docker
func testUserContractClaimCreate(client *sdk.ChainClient, withSyncResult bool, isIgnoreSameContract bool, usernames ...string) string {resp, err := createUserContract(client, claimContractName, claimVersion, claimByteCodePath,common.RuntimeType_DOCKER_GO, []*common.KeyValuePair{}, withSyncResult, usernames...)if err != nil {if !isIgnoreSameContract {log.Fatalln(err)} else {fmt.Printf("CREATE claim contract failed, err: %s, resp: %+v\n", err, resp)}} else {fmt.Printf("CREATE claim contract success, resp: %+v\n", resp)}if resp != nil {return resp.TxId}return ""
}func createUserContract(client *sdk.ChainClient, contractName, version, byteCodePath string, runtime common.RuntimeType,kvs []*common.KeyValuePair, withSyncResult bool, usernames ...string) (*common.TxResponse, error) {payload, err := client.CreateContractCreatePayload(contractName, version, byteCodePath, runtime, kvs)if err != nil {return nil, err}payload = client.AttachGasLimit(payload, &common.Limit{GasLimit: 60000000,})//endorsers, err := examples.GetEndorsers(payload, usernames...)endorsers, err := examples.GetEndorsersWithAuthType(client.GetHashType(),client.GetAuthType(), payload, usernames...)if err != nil {return nil, err}resp, err := client.SendContractManageRequest(payload, endorsers, createContractTimeout, withSyncResult)if err != nil {return resp, err}err = examples.CheckProposalRequestResp(resp, true)if err != nil {return resp, err}return resp, nil
}
区块链学习2-合约开发相关推荐
- 区块链学习-智能合约与ICO
什么是"以太坊"? 以太坊是由程序员Vitalik Buterin创立的,是比特币交易的替代品.比特币被严格用作加密电子货币,或被视作一种转移货币价值的手段.然而,相同的区块链技术 ...
- 区块链学习5:智能合约Smart contract原理及发展历程科普知识
☞ ░ 前往老猿Python博文目录 ░ 一.智能合约的定义 通俗来说,智能合约就是一种在计算机系统上,当一定条件满足的情况下可被自动执行的合约,智能合约体现为一段代码及其运行环境.例如银行信用卡的自 ...
- 【区块链学习最全教程】学习 Solidity,全栈 Web3,Javascript 和区块链开发
Chainlink 开发者社区发布了一个关于全栈 web3,solidity 和区块链开发的完整视频教程.本视频教程由 Chainlink 开发者大使 Patrick Collins 讲解.教程由浅入 ...
- 美化UI合约区块链学习版系统+交易大厅
简介: 美化UI合约区块链学习版系统+交易大厅 亲测环境:Win+宝塔+Apache+php5.6+mysql5.5 数据库配置文件:/APP/Conf/config.php 设置TP伪静态 后台地址 ...
- 尚硅谷以太坊区块链学习之NFT智能合约(6)
尚硅谷以太坊区块链学习之NFT智能合约(6) 前言 一.NFT智能合约 1.智能合约代码 2.智能合约推送 3.具体调用 二.具体使用 三.NFT商家智能合约 前言 提示:服务外包区块链学习 5被ba ...
- 区块链学习笔记21——ETH智能合约
区块链学习笔记21--ETH智能合约 学习视频:北京大学肖臻老师<区块链技术与应用> 笔记参考:北京大学肖臻老师<区块链技术与应用>公开课系列笔记--目录导航页 智能合约简介 ...
- 剑英的区块链学习手记(二)
孙子说,知己知彼,百战不殆. 咱是通过小蚁学习区块链技术的. 开工之前,先了解一下小蚁的资料家族. 小蚁网站 https://www.antshares.org/ 小蚁源码 https://githu ...
- 月薪 100K?还不来看看区块链学习清单?字字都是 Money!
点击上方"CSDN",选择"置顶公众号" 关键时刻,第一时间送达! CSDN粉丝今日专属购书福利:全场书籍优惠,满100减50!仅限当日使用. 初春乍寒,又到了 ...
- 区块链学习笔记23——ETH反思
区块链学习笔记23--ETH反思 学习视频:北京大学肖臻老师<区块链技术与应用> 笔记参考:北京大学肖臻老师<区块链技术与应用>公开课系列笔记--目录导航页 智能合约真的智能吗 ...
最新文章
- flash写保护原理_一种基于flash写保护的防止flash被意外篡改的方法与流程
- POJ2195费用流+BFS建图
- Linux操作系统用户登录失败次数过多被锁定的解决方法
- 物理化学 焓变的计算,学会状态的转变
- 微信小游戏“跳一跳”,Python“外挂”已上线
- 在DataGridView中显示合计,并且合计始终在最后一行
- 自动驾驶 5-2 使用 PID 进行纵向速度控制 Longitudinal Speed Control with PID
- 尚硅谷大数据课程flink1.13代码实现与笔记记录
- c语言知识点总完整版pdf,C语言知识点总结 重点版.pdf
- hybrid app支持html5,Hybrid App 接入
- PHP解决验证码无法显示的方法
- python计算加权平均分_python – 使用numpy.average的加权平均值
- 多个mysql共存_双mysql共存(MySQL8.0与MySQL5.7)
- Python实现检测字符串是否全为汉字(含生僻字)
- 关于浏览器的几个高度和宽度
- android英语字典(源代码),android英语字典(内含源码哦)
- PPT文件设置打开密码的两种方法
- 十、什么是临界资源及如何访问临界资源
- 对随机变量值域的思考
- 用网络调试助手UDP TCP测试