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开发相关推荐

  1. Hyperledger Fabric 1.0 实战开发系列 第二课 Fabric环境搭建

    一.安装GO语言 下载最新版的go 打开Terminal,输入命令(以下命令都是以root管理员的角色进行的) su 输入密码:***** wget https://storage.googleapi ...

  2. Hyperledger Fabric 1.0 实战开发系列 第四课 搭建node.js服务器

    接下来我要做的是用fabric sdk来做出应用程序,代替CLI与整个区块链网络交互.并且实现一个http API,向社区提供一个简单的接口,使社区轻松的与区块链交互. 官方虽然提供了Node.JS, ...

  3. Hyperledger Fabric 1.0 实战开发系列 第一课 系统环境搭建

    有人说讲了那么多理论,总该来点实际动手的干货,嘿嘿,所以笔者开始写点实战,本人电脑为window10系统,故采用虚拟机virtualBox+Ubuntu来进行实战 1.下载virtualBox,可以到 ...

  4. Hyperledger Fabric 1.0 实战开发系列 第⑤课 fabric 证书解析

    通过cryptogen生成所有证书文件后,以peerOrgannizations的第一个组织树org1为例,每个目录和对应文件的功能如下: ca: 存放组织的根证书和对应的私钥文件,默认采用EC算法, ...

  5. Hyperledger Fabric 1.0 从零开始(十二)——fabric-sdk-java应用

    Hyperledger Fabric 1.0 从零开始(十)--智能合约(参阅:Hyperledger Fabric Chaincode for Operators--实操智能合约) Hyperled ...

  6. 三、主流区块链技术特点及Hyperledger Fabric V1.0版本特点

    一.Hyperledger fabric V1.0 架构 1.逻辑架构: 2.区块链网络 3.运行时架构 二.架构总结 1.架构要点 分拆Peer的功能,将Blockchain的数据维护和共识服务进行 ...

  7. 搭建区块链浏览器——基于hyperledger fabric 1.0,MySQL容器

    搭建区块链浏览器--基于hyperledger fabric 1.0,MySQL容器 区块链 hyperledger fabric 浏览器 MySQL docker  Contents 环境要求 分支 ...

  8. Hyperledger Fabric 2.0 官方文档中文版 第6章 教程(上)

    Hyperledger Fabric 2.0 官方文档中文版第6章 教程上 总目录 6.教程(上) 将智能合约部署到通道 启动网络 Logspout设置 打包智能合约 安装链码包 批准链码定义 将链码 ...

  9. 3.Hyperledger Fabric v2.0 CA组件

    Hyperledger Fabric v2.0 CA组件 目的: 通过CA服务生成msp证书和tls证书,并启动fabric网络 由于使用CA生成证书时,需要注册为各个组织生成证书,为了便于理解,所以 ...

最新文章

  1. hdu1711 KMP模板
  2. Java 8 - 07 复合 Lambda 表达式
  3. 新宝来引擎盖怎么打开
  4. [网络流24题]太空飞行计划
  5. 《LINUX内核设计与实现》第五章学习总结
  6. 在CentOS Linux上安装oracle11g之二 安装oracle11g
  7. Vlc支持IE 360 低版本的Google浏览器
  8. windows环境下zookeeper做成服务并启动
  9. [转]飞秋使用说明与常见问题解决方法
  10. [AHK]获取通达信软件上的股票代码
  11. 智能脚本植入与CBSS+
  12. IDE工具(17) eclipse创建ftl文件具体步骤
  13. 26. 平衡二叉排序树
  14. BeanAir无线传感器方案
  15. 微信小程序 首页弹出广告的demo
  16. 实验一:交换机和路由器的基本配置
  17. React路由官方网站
  18. PCI GXL学习之安装篇
  19. 已注销主体的公众号迁移办理流程及方法
  20. CogColorExtractorTool工具功能

热门文章

  1. 用.net4中的DynamicObject实现简单AOP
  2. 图像白化MATLAB代码实现
  3. 【Paper】Origin绘制误差棒图(标准差围绕均值)
  4. 云炬随笔20211001
  5. 云炬随笔20170901
  6. 燃烧学往年精选真题解析2018-01-01
  7. python函数编程训练题_Python文件与函数练习题
  8. matlab神经网络2:数据拟合
  9. win7下不能替换系统文件的解决办法
  10. C#与Javascript变量、函数之间的相互调用2008年11月28日 星期五 05:28 P.M.1.如何在JavaScript访问C#函数?