Hyperledger Fabric 1.0 实战开发系列 第三课 chaincode开发
chaincode是由go语言写的,实现了定义的接口。其他语言例如JAVA也是支持的。通过application体积的transaction,chaincode可以初始化并管理Ledger状态。
一个chaincode创建的Ledger状态是独立的,不能被其他chaincode直接访问。在合适的许可下,chaincode能够调用在相同网络下的其他chaincode用于访问其Ledger状态。
接下来,我们以chaincode开发者的视野来看看chaincode。下面我们以一个chaincode案例来看看chaincode Shim API的每一个方法。
1.Chaincode API
每一个chaincode需要实现Chaincode接口,其方法是用于响应接收到的transaction。当chaincode接收到instantiate或者upgrade transaction时Init方法被调用了,以便chaincode能够执行任何必要的初始化,包括application state的初始化。当chaincode接收到invoke transaction时调用invoke方法,用于处理transaction proposal。
“shim”API中其他的接口是 ChaincodeStubInterface 用于访问及改变Ledger,以及在chaincode之间调用。
在本教程中,我们将通过实现简单的chaincode应用程序(管理简单的“资产”)来演示这些API的使用。
2.简单的资产chaincode
我们的application是一个基本的样例chaincode,用于在Ledger上创建资产(键值对)。
推荐使用vscode进行go代码编写,
打开终端并运行下面的命令:
sudo add-apt-repository ppa:ubuntu-desktop/ubuntu-make
sudo apt-get update
sudo apt-get install ubuntu-make
如果已经安装,运行下面的命令:
umake web visual-studio-code
请注意,在安装过程中, 你会问,给出路径 insatllation 软件包. 在那之后它会询问提交您的权限,安装 Visual Studio 代码. 请按 ‘’ 若要安装 (‘’ 表示接受条款和条件).
设置GOPATH
vscode安装go插件时会提示GOPATH not set错误,则打开launch.json在里面env中设置
安装vscode go
在vscode应用商店里面搜索go,点击安装即可。2.1 选择代码的位置首选需要确定Go的环境被安装以及被合适的配置。为了简单起见,我们使用以下命令:
mkdir -p $GOPATH/src/asset && cd $GOPATH/src/asset
接下来,我们创建源码文件
touch asset.go
2.2 引入包
每一个chaincode都实现了Chaincode接口 <https://github.com/hyperledger/fabric/blob/master/core/chaincode/shim/interfaces.go#L28>,特别是Init以及Invoke函数。因此,我们引入
package mainimport ("fmt""github.com/hyperledger/fabric/core/chaincode/shim""github.com/hyperledger/fabric/protos/peer" )
2.3 初始化chaincode
我们的类名叫SimpleAsset
type SimpleAsset struct {
}
接下来,我们事先Init函数
// Init is called during chaincode instantiation to initialize any data. func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {}
注:chaincode upgrade也调用这个函数。当一个chaincode要升级时,确保合适修正Init函数。如果没有需要迁移的东西,或者没有需要在升级时初始化的东西,需要提供的空的init函数。
接下来,我们调用ChaincodeStubInterface.GetStringArgs方法获取Init中需要的参数,并检查参数的有效性。我们期望获取的参数是一个键值对。
// Init is called during chaincode instantiation to initialize any // data. Note that chaincode upgrade also calls this function to reset // or to migrate data, so be careful to avoid a scenario where you // inadvertently clobber your ledger's data! func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {// Get the args from the transaction proposalargs := stub.GetStringArgs()if len(args) != 2 {return shim.Error("Incorrect arguments. Expecting a key and a value")} }
接下来,由于我们的调用是有效的,我们将会在Ledger上存储初始状态。为了实现状态的存储,我们将会调用ChaincodeStubInterface.PutState方法,并把键值作为参数进行输入。假设一切都工作正常,则会返回一个peer.Response对象,表面初始化成功。
// Init is called during chaincode instantiation to initialize any // data. Note that chaincode upgrade also calls this function to reset // or to migrate data, so be careful to avoid a scenario where you // inadvertently clobber your ledger's data! func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {// Get the args from the transaction proposalargs := stub.GetStringArgs()if len(args) != 2 {return shim.Error("Incorrect arguments. Expecting a key and a value")}// Set up any variables or assets here by calling stub.PutState()// We store the key and the value on the ledgererr := stub.PutState(args[0], []byte(args[1]))if err != nil {return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0]))}return shim.Success(nil) }
2.4 调用chaincode
首先,添加Invoke函数签名
// Invoke is called per transaction on the chaincode. Each transaction is // either a 'get' or a 'set' on the asset created by Init function. The 'set' // method may create a new asset by specifying a new key-value pair. func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {}
就像上述Init的函数那样,我们需要通过ChaincodeStubInterface获取参数。Invoke函数的参数就是需要调用chaincode应用的名称。在我们的例子中,我们的应用有两个简单的函数set与get,允许asset的值被设定,同时允许获取现在的状态。我们首先调用ChaincodeStubInterface.GetFunctionAndParameters用来获取chaincode应用的函数名称与参数。
// Invoke is called per transaction on the chaincode. Each transaction is // either a 'get' or a 'set' on the asset created by Init function. The Set // method may create a new asset by specifying a new key-value pair. func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {// Extract the function and args from the transaction proposalfn, args := stub.GetFunctionAndParameters()}
接着,我们设置set与get函数名称,并调用这些chaincode应用函数,通过shim返回一个合适的响应。Error函数将会把一个响应序列化成gRPC protobuf消息。
// Invoke is called per transaction on the chaincode. Each transaction is // either a 'get' or a 'set' on the asset created by Init function. The Set // method may create a new asset by specifying a new key-value pair. func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {// Extract the function and args from the transaction proposalfn, args := stub.GetFunctionAndParameters()var result stringvar err errorif fn == "set" {result, err = set(stub, args)} else {result, err = get(stub, args)}if err != nil {return shim.Error(err.Error())}// Return the result as success payloadreturn shim.Success([]byte(result)) }
2.5 实现chaincode应用
我们的chaincode应用实现了两个函数,能够通过Invoke进行调用。接下来实现这些函数。就像我们上面所提到的,我使用chaincode shim API的ChaincodeStubInterface.PutState与ChaincodeStubInterface.GetState来访问access的状态。
// Set stores the asset (both key and value) on the ledger. If the key exists, // it will override the value with the new one func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {if len(args) != 2 {return "", fmt.Errorf("Incorrect arguments. Expecting a key and a value")}err := stub.PutState(args[0], []byte(args[1]))if err != nil {return "", fmt.Errorf("Failed to set asset: %s", args[0])}return args[1], nil }// Get returns the value of the specified asset key func get(stub shim.ChaincodeStubInterface, args []string) (string, error) {if len(args) != 1 {return "", fmt.Errorf("Incorrect arguments. Expecting a key")}value, err := stub.GetState(args[0])if err != nil {return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err)}if value == nil {return "", fmt.Errorf("Asset not found: %s", args[0])}return string(value), nil }
2.6 合并上述代码
package mainimport ("fmt""github.com/hyperledger/fabric/core/chaincode/shim""github.com/hyperledger/fabric/protos/peer" )// SimpleAsset implements a simple chaincode to manage an asset type SimpleAsset struct { }// Init is called during chaincode instantiation to initialize any // data. Note that chaincode upgrade also calls this function to reset // or to migrate data. func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {// Get the args from the transaction proposalargs := stub.GetStringArgs()if len(args) != 2 {return shim.Error("Incorrect arguments. Expecting a key and a value")}// Set up any variables or assets here by calling stub.PutState()// We store the key and the value on the ledgererr := stub.PutState(args[0], []byte(args[1]))if err != nil {return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0]))}return shim.Success(nil) }// Invoke is called per transaction on the chaincode. Each transaction is // either a 'get' or a 'set' on the asset created by Init function. The Set // method may create a new asset by specifying a new key-value pair. func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {// Extract the function and args from the transaction proposalfn, args := stub.GetFunctionAndParameters()var result stringvar err errorif fn == "set" {result, err = set(stub, args)} else { // assume 'get' even if fn is nilresult, err = get(stub, args)}if err != nil {return shim.Error(err.Error())}// Return the result as success payloadreturn shim.Success([]byte(result)) }// Set stores the asset (both key and value) on the ledger. If the key exists, // it will override the value with the new one func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {if len(args) != 2 {return "", fmt.Errorf("Incorrect arguments. Expecting a key and a value")}err := stub.PutState(args[0], []byte(args[1]))if err != nil {return "", fmt.Errorf("Failed to set asset: %s", args[0])}return args[1], nil }// Get returns the value of the specified asset key func get(stub shim.ChaincodeStubInterface, args []string) (string, error) {if len(args) != 1 {return "", fmt.Errorf("Incorrect arguments. Expecting a key")}value, err := stub.GetState(args[0])if err != nil {return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err)}if value == nil {return "", fmt.Errorf("Asset not found: %s", args[0])}return string(value), nil }// main function starts up the chaincode in the container during instantiate func main() {if err := shim.Start(new(SimpleAsset)); err != nil {fmt.Printf("Error starting SimpleAsset chaincode: %s", err)} }
2.7 build chaincode
编译chaincode
go get -u --tags nopkcs11 github.com/hyperledger/fabric/core/chaincode/shim go build --tags nopkcs11
接下来测试chaincode
2.8 使用dev模式测试
一般来说,peer启动并持有chaincode。然而在开发模式下,chaincode由用户build并启动。在快速代码/构建/运行/调试周期周转期间的链码开发阶段,此模式非常有用。
我们通过为利用预先生成的order和channel artifacts来启动一个简单的开发网络的“开发模式”。 因此,用户可以立即编译chaincode和调用函数。
3.安装hyberLedger fabric 样例
请先安装hyberLedger fabric 样例。
进入fabric-samples以及chaincode-docker-devmode目录
cd chaincode-docker-devmode
4.下载docker镜像
我们需要四个Docker镜像用于开发模式允许docker compose script.脚本,如果你已经安装了fabric-samples仓库克隆,并且按照说明下载了platform-specific-binaries,接下来你应该在本地按照Docker镜像。输入docker images命令去展示Docker镜像。应该能看到如下:
docker images REPOSITORY TAG IMAGE ID CREATED SIZE hyperledger/fabric-tools latest e09f38f8928d 4 hours ago 1.32 GB hyperledger/fabric-tools x86_64-1.0.0-rc1-snapshot-f20846c6 e09f38f8928d 4 hours ago 1.32 GB hyperledger/fabric-orderer latest 0df93ba35a25 4 hours ago 179 MB hyperledger/fabric-orderer x86_64-1.0.0-rc1-snapshot-f20846c6 0df93ba35a25 4 hours ago 179 MB hyperledger/fabric-peer latest 533aec3f5a01 4 hours ago 182 MB hyperledger/fabric-peer x86_64-1.0.0-rc1-snapshot-f20846c6 533aec3f5a01 4 hours ago 182 MB hyperledger/fabric-ccenv latest 4b70698a71d3 4 hours ago 1.29 GB hyperledger/fabric-ccenv x86_64-1.0.0-rc1-snapshot-f20846c6 4b70698a71d3 4 hours ago 1.29 GB
5.启动网络
docker-compose -f docker-compose-simple.yaml up
上述代码启动了包括SingleSampleMSPSolo
orderer profile的网络,同时启动开发模式的peer。这个启动了另外两个容器,一个是chaincode的环境以及与chaincode交互的CLI。在CLI容器中进行创建与加入channel的命令,因此我们可以开始chaincode的调用。
6.build与启动chaincode
docker exec -it chaincode bash
进入容器,
root@d2629980e76b:/opt/gopath/src/chaincode#
接下来,编译chaincode
cd asset go build
现在运行chaincode:
CORE_PEER_ADDRESS=peer:7051 CORE_CHAINCODE_ID_NAME=mycc:0 ./asset
peer启动了chaincode,以及chaincode日志表明peer成功注册了chaincode。该阶段chaincode没有与任何channel产生关联。这在使用实例化命令的后续步骤中完成。
7.使用chaincode
即使现在在--peer-chaincodedev模式下,仍然需要安装chaincode,以便生命周期的chaincode能够正常检查。
我们利用CLI容器去调用这些方法
docker exec -it cli bash
peer chaincode install -p chaincodedev/chaincode/asset -n mycc -v 0 peer chaincode instantiate -n mycc -v 0 -c '{"Args":["a","10"]}' -C myc
接下来改变a的值为20.
peer chaincode invoke -n mycc -c '{"Args":["set", "a", "20"]}' -C myc
最后查询
peer chaincode query -n mycc -c '{"Args":["query","a"]}' -C myc
8.测试新的chaincode
这个案例中,我们只实现了asset。我们可以很轻松的测试其他的chaincode通过吧这些chaincode加入到chaincode子目录下,然后重启网络。此时,他们能够在chaincode容器中被访问。
Hyperledger Fabric 1.0 实战开发系列 第三课 chaincode开发相关推荐
- Hyperledger Fabric 1.0 实战开发系列 第二课 Fabric环境搭建
一.安装GO语言 下载最新版的go 打开Terminal,输入命令(以下命令都是以root管理员的角色进行的) su 输入密码:***** wget https://storage.googleapi ...
- Hyperledger Fabric 1.0 实战开发系列 第四课 搭建node.js服务器
接下来我要做的是用fabric sdk来做出应用程序,代替CLI与整个区块链网络交互.并且实现一个http API,向社区提供一个简单的接口,使社区轻松的与区块链交互. 官方虽然提供了Node.JS, ...
- Hyperledger Fabric 1.0 实战开发系列 第一课 系统环境搭建
有人说讲了那么多理论,总该来点实际动手的干货,嘿嘿,所以笔者开始写点实战,本人电脑为window10系统,故采用虚拟机virtualBox+Ubuntu来进行实战 1.下载virtualBox,可以到 ...
- Hyperledger Fabric 1.0 实战开发系列 第⑤课 fabric 证书解析
通过cryptogen生成所有证书文件后,以peerOrgannizations的第一个组织树org1为例,每个目录和对应文件的功能如下: ca: 存放组织的根证书和对应的私钥文件,默认采用EC算法, ...
- Hyperledger Fabric 1.0 从零开始(十二)——fabric-sdk-java应用
Hyperledger Fabric 1.0 从零开始(十)--智能合约(参阅:Hyperledger Fabric Chaincode for Operators--实操智能合约) Hyperled ...
- 三、主流区块链技术特点及Hyperledger Fabric V1.0版本特点
一.Hyperledger fabric V1.0 架构 1.逻辑架构: 2.区块链网络 3.运行时架构 二.架构总结 1.架构要点 分拆Peer的功能,将Blockchain的数据维护和共识服务进行 ...
- 搭建区块链浏览器——基于hyperledger fabric 1.0,MySQL容器
搭建区块链浏览器--基于hyperledger fabric 1.0,MySQL容器 区块链 hyperledger fabric 浏览器 MySQL docker Contents 环境要求 分支 ...
- Hyperledger Fabric 2.0 官方文档中文版 第6章 教程(上)
Hyperledger Fabric 2.0 官方文档中文版第6章 教程上 总目录 6.教程(上) 将智能合约部署到通道 启动网络 Logspout设置 打包智能合约 安装链码包 批准链码定义 将链码 ...
- 3.Hyperledger Fabric v2.0 CA组件
Hyperledger Fabric v2.0 CA组件 目的: 通过CA服务生成msp证书和tls证书,并启动fabric网络 由于使用CA生成证书时,需要注册为各个组织生成证书,为了便于理解,所以 ...
最新文章
- hdu1711 KMP模板
- Java 8 - 07 复合 Lambda 表达式
- 新宝来引擎盖怎么打开
- [网络流24题]太空飞行计划
- 《LINUX内核设计与实现》第五章学习总结
- 在CentOS Linux上安装oracle11g之二 安装oracle11g
- Vlc支持IE 360 低版本的Google浏览器
- windows环境下zookeeper做成服务并启动
- [转]飞秋使用说明与常见问题解决方法
- [AHK]获取通达信软件上的股票代码
- 智能脚本植入与CBSS+
- IDE工具(17) eclipse创建ftl文件具体步骤
- 26. 平衡二叉排序树
- BeanAir无线传感器方案
- 微信小程序 首页弹出广告的demo
- 实验一:交换机和路由器的基本配置
- React路由官方网站
- PCI GXL学习之安装篇
- 已注销主体的公众号迁移办理流程及方法
- CogColorExtractorTool工具功能
热门文章
- 用.net4中的DynamicObject实现简单AOP
- 图像白化MATLAB代码实现
- 【Paper】Origin绘制误差棒图(标准差围绕均值)
- 云炬随笔20211001
- 云炬随笔20170901
- 燃烧学往年精选真题解析2018-01-01
- python函数编程训练题_Python文件与函数练习题
- matlab神经网络2:数据拟合
- win7下不能替换系统文件的解决办法
- C#与Javascript变量、函数之间的相互调用2008年11月28日 星期五 05:28 P.M.1.如何在JavaScript访问C#函数?