概述

智能合约本质上是运行在某种环境(例如虚拟机)中的一段代码逻辑。

长安链的智能合约是运行在长安链上的一组“动态代码”,类似于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)}
}

编译合约

编译几个必要条件:

  1. 需要在linux环境下编译,如果在mac平台编译,需要把build.sh里面的go build main.go改成CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go

  2. 代码入口包名必须为main 见步骤1,2

  3. 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-合约开发相关推荐

  1. 区块链学习-智能合约与ICO

    什么是"以太坊"? 以太坊是由程序员Vitalik Buterin创立的,是比特币交易的替代品.比特币被严格用作加密电子货币,或被视作一种转移货币价值的手段.然而,相同的区块链技术 ...

  2. 区块链学习5:智能合约Smart contract原理及发展历程科普知识

    ☞ ░ 前往老猿Python博文目录 ░ 一.智能合约的定义 通俗来说,智能合约就是一种在计算机系统上,当一定条件满足的情况下可被自动执行的合约,智能合约体现为一段代码及其运行环境.例如银行信用卡的自 ...

  3. 【区块链学习最全教程】学习 Solidity,全栈 Web3,Javascript 和区块链开发

    Chainlink 开发者社区发布了一个关于全栈 web3,solidity 和区块链开发的完整视频教程.本视频教程由 Chainlink 开发者大使 Patrick Collins 讲解.教程由浅入 ...

  4. 美化UI合约区块链学习版系统+交易大厅

    简介: 美化UI合约区块链学习版系统+交易大厅 亲测环境:Win+宝塔+Apache+php5.6+mysql5.5 数据库配置文件:/APP/Conf/config.php 设置TP伪静态 后台地址 ...

  5. 尚硅谷以太坊区块链学习之NFT智能合约(6)

    尚硅谷以太坊区块链学习之NFT智能合约(6) 前言 一.NFT智能合约 1.智能合约代码 2.智能合约推送 3.具体调用 二.具体使用 三.NFT商家智能合约 前言 提示:服务外包区块链学习 5被ba ...

  6. 区块链学习笔记21——ETH智能合约

    区块链学习笔记21--ETH智能合约 学习视频:北京大学肖臻老师<区块链技术与应用> 笔记参考:北京大学肖臻老师<区块链技术与应用>公开课系列笔记--目录导航页 智能合约简介 ...

  7. 剑英的区块链学习手记(二)

    孙子说,知己知彼,百战不殆. 咱是通过小蚁学习区块链技术的. 开工之前,先了解一下小蚁的资料家族. 小蚁网站 https://www.antshares.org/ 小蚁源码 https://githu ...

  8. 月薪 100K?还不来看看区块链学习清单?字字都是 Money!

    点击上方"CSDN",选择"置顶公众号" 关键时刻,第一时间送达! CSDN粉丝今日专属购书福利:全场书籍优惠,满100减50!仅限当日使用. 初春乍寒,又到了 ...

  9. 区块链学习笔记23——ETH反思

    区块链学习笔记23--ETH反思 学习视频:北京大学肖臻老师<区块链技术与应用> 笔记参考:北京大学肖臻老师<区块链技术与应用>公开课系列笔记--目录导航页 智能合约真的智能吗 ...

最新文章

  1. flash写保护原理_一种基于flash写保护的防止flash被意外篡改的方法与流程
  2. POJ2195费用流+BFS建图
  3. Linux操作系统用户登录失败次数过多被锁定的解决方法
  4. 物理化学 焓变的计算,学会状态的转变
  5. 微信小游戏“跳一跳”,Python“外挂”已上线
  6. 在DataGridView中显示合计,并且合计始终在最后一行
  7. 自动驾驶 5-2 使用 PID 进行纵向速度控制 Longitudinal Speed Control with PID
  8. 尚硅谷大数据课程flink1.13代码实现与笔记记录
  9. c语言知识点总完整版pdf,C语言知识点总结 重点版.pdf
  10. hybrid app支持html5,Hybrid App 接入
  11. PHP解决验证码无法显示的方法
  12. python计算加权平均分_python – 使用numpy.average的加权平均值
  13. 多个mysql共存_双mysql共存(MySQL8.0与MySQL5.7)
  14. Python实现检测字符串是否全为汉字(含生僻字)
  15. 关于浏览器的几个高度和宽度
  16. android英语字典(源代码),android英语字典(内含源码哦)
  17. PPT文件设置打开密码的两种方法
  18. 十、什么是临界资源及如何访问临界资源
  19. 对随机变量值域的思考
  20. 用网络调试助手UDP TCP测试

热门文章

  1. SQL难学吗,有什么好的学习建议?
  2. gitlab artifacts too large
  3. 计算机视觉项目实战-图像特征检测harris、sift、特征匹配
  4. 基于人脸识别的“带口罩”系统-python完整实现
  5. 为什么要配置环境变量,配置环境变量有什么好处?
  6. PYTHON实现将一个文件夹下的名字满足条件的图片拷贝复制到另一个文件夹路径
  7. ubuntu安装和卸载软件命令
  8. 前端规范 - 前端项目开发规范
  9. [图形学] 经典算法 - Kajiya三维纹理渲染毛发
  10. 元器件中电容的小小知识 2021-09-06