• -------------------------------------------------------------
  • ====================================

07-在开发者模式下调试chaincode

区块链 dewbay 4年前 (2020-01-06) 1648次浏览 已收录 0个评论 扫描二维码

最近跟着 HyperLedger 中文文档在学习ChainCode开发的时候,对官方文档的文章结构很是不理解。首先叫我们编写一个简单资产管理的 chainCode,最后调试的时候,竟然是调试官方提供的版本。所以决定把这与部分重新整理一下。讲解一下怎样编写,调试自己的ChainCode。全文的结构如下:

07-在开发者模式下调试chaincode
全文结构

前言

目前编写ChainCode的时候,并没有没有 IDE 来供我们使用。因为我们的ChainCode是运行在区块链的节点上。这一点和编写后端程序有点相似,比如你用 Java 写一个后端程序,调试的时候,你需要开启一个 Tomcat 服务器,才能够进行调试。由于 java 后台开发技术比较成熟,很多的很好的框架已经可以帮助你处理这些环境配置,服务器开启等,让你专注于业务逻辑的开发,比如 SpringBoot 框架。

但是,目前在ChainCode的编写调试过程中,并没有这样子的框架。我们需要自己搭建好 Fabric 网络,自己手动编写,编译并调试ChainCode。为了方便我们的调试,这里,我们首先准备好 ChainCode 的开发环境。


1.开发环境的准备

我们这里的开发环境,是建立在官方 fabric-sample 项目提供的网络基础之上。具体步骤如下:

  • 下载 fabric-sample 源码
git clone https://github.com/hyperledger/fabric-samples.git
cd fabric-samples

这个项目的目录如下:

07-在开发者模式下调试chaincode
fabric-sample 目录结构

这里,很多目录是 HyperLedger 官方提供的小 demo。介绍两个主要的目录。

第一个是 chaincode.进入这个目录,我们可以看到一下几个文件,这些文件都是不同项目中要用到的 ChainCode。

abac  chaincode_example02  fabcar  hyperledger  marbles02  sacc

比如,fabCar 目录里面,就是我们之前 FabCar 项目中智能合约存储的地方。

在这里为我们接下来的项目建立一个文件夹:

mkdir mychaincode

接下来,我们将会在这个目录中编写我们的 ChainCode。

第二个是 chaincode-docker-devmode 目录。在这个目录中,我们可以借助构建自带区块链样例网络时已经预先生成好的 order 和 channel 来启动“开发者模式”。这样,用户可以立即编译 chaincode 并调用函数。

接下来,我们将会在这个目录中调试我们编写的 ChainCode。包括编译,安装,实例化等等。


2.编写 ChainCode

首先,我们进入刚刚创建的 mychaincode 文件夹:

cd ~/fabric-samples/chaincode/mychaincode

新建一个 mychaincode.go 文件,并编写相关的内容。关于 ChainCode 如何编写,前文已经介绍过了,这里不在赘述。直接贴上代码:

//这里是一个简单资产 ChainCode 的编码。关于源码的解读,写在了注释里面。
// This is my first ChainCode
/*
 * 引入相关的包
 */

package main

import (
	"fmt"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	"github.com/hyperledger/fabric/protos/peer"
)

// 定义一个简单资产结构体
type SimpleAsset struct {
}


//为 SimpleAsset 结构体实现 Init 接口函数。这个函数会在 ChainCode 初始化,或者升级的时候调用。
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
	// 从交易提案中获取参数
	args := stub.GetStringArgs()
	if len(args) != 2 {
		return shim.Error("Incorrect arguments. Expecting a key and a value")
	}

	//通过 stub.PutState() 来讲数据写入到账本中。

	// 将 key-value 键值对写入到账本中。
	err := 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 接口函数。
func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
	// 从交易提案中获取要调用的功能函数名。
	fn, args := stub.GetFunctionAndParameters()

	var result string
	var err error
	if fn == "set" {
		result, err = set(stub, args)
	} else { // assume 'get' even if fn is nil
		result, err = get(stub, args)
	}
	if err != nil {
		return shim.Error(err.Error())
	}

	// Return the result as success payload
	return shim.Success([]byte(result))
}


// Set 功能函数,用于将数据写入到账本中。
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 功能函数,用于查询账本中函数的值。
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 函数,用于在实例化过程中,在容器中启动 ChainCode。
func main() {
	if err := shim.Start(new(SimpleAsset)); err != nil {
		fmt.Printf("Error starting SimpleAsset chaincode: %s", err)
	}
}



3.调试 ChainCode

在 Fabric 中,调用 chainCode 有两种方式,一种是通过 SDK 编写应用程序来调用,比如《HyperLedger 实战-编写一个区块链应用》中的 fabcar 项目中,通过 nodejs 程序调用 ChainCode。还有一种方式,就是使用 cli 命令来调用 ChainCode。由于这篇文章中,我们用 cli 命令行来调用 ChainCode。

调试 ChainCode 主要分为三个步骤:

  1. 启动 Fabric 网络。
  2. 编译安装 chainCode。
  3. 调用 ChainCode。

这三个步骤,需要我们在开发者模式下完成,也就是进入 chaincode-docker-devmode 目录下面打开三个独立的终端。

  • 1 号终端
docker-compose -f docker-compose-simple.yaml up

上述指令启动了一个带有 SingleSampleMSPSoloorderer profile 的网络,并将节点在“开发者模式”下启动。它还启动了另外两个容器:一个包含 chaincode 运行环境;另一个是 CLI 命令行,可与 chaincode 进行交互。创建并加入 channel(管道)的指令内嵌于 CLI 容器中。

  • 2 号终端
docker exec -it chaincode bash

执行完上述指令是进入了 cli 容器,您应该会看到如下内容:

root@b46549c6be95:/opt/gopath/src/chaincode#

ls 可以看到如下目录

abac chaincode_example02 fabcar hyperledger marbles02 mychaincode sacc

进入我们的目录 mychaincode,可以看到我们编写的 chainCode 源码:

07-在开发者模式下调试chaincode

下面编译我们的 chaincode:

go build

运行 ls 命令,可以看到,多了一个可执行的 chainCode 文件。

07-在开发者模式下调试chaincode

现在运行 chaincode:

CORE_PEER_ADDRESS=peer:7052 CORE_CHAINCODE_ID_NAME=mycc:0 ./mychaincode

Chaincode 被 peer 节点启动,chaincode 日志表明 peer 节点成功注册。

注意:

现阶段 chaincode 还没有与任何 channel 关联。这会在接下来使用 instantiate 指令后实现.
CORE_PEER_ADDRESS=peer:7052。
在中文文档中,参数为 7051 是不对的,应该改为 7052。

  • 3 号终端

即便处于 peer-chaincodedev 模式,安装 chaincode 这一步仍必不可少,这样生命周期系统 chaincode 才能正常进行检查。

下面我们将进入 CLI 容器进行 chaincode 调用。

docker exec -it cli bash
peer chaincode install -p chaincodedev/chaincode/mychaincode -n mycc -v 0
peer chaincode instantiate -n mycc -v 0 -c '{"Args":["a","10"]}' -C myc
在 CLI 内部会为 mychaincode 创建 SignedChaincodeDeploymentSpec,并将其发送到本地 peer 节点。这些节点会调用 LSCC 上的 Install 方法。上述的-p 选项指明 chaincode 的路径,其必须在用户的 GOPATH 目录下(比如$GOPATH/src/sacc)。

完整的命令选项详见:HyperLedger 官方文档 CLI 部分。

现在我们执行一次将 a 的值设为 20 的调用:

peer chaincode invoke -n mycc -c '{"Args":["set", "a", "20"]}' -C myc

最后查询 a 的值,我们会看到 20。

peer chaincode query -n mycc -c '{"Args":["query","a"]}' -C myc

值此,我们实现了 mychaincode 从编写到调试的一系列操作。可以通过将不同的 chaincode 添加到 chaincode 子目录下重启网络来轻松地测试它们。重启它们将可在 chaincode 容器中被访问。

4.玄学级 Bug

在虚拟机环境下,操作终端 2 使用如下命令运行 chainCode 的时候:

现在运行 chaincode:

CORE_PEER_ADDRESS=peer:7051 CORE_CHAINCODE_ID_NAME=mycc:0./mychaincode

出现了如下错误:

2018-04-11 03:24:16.466 UTC [shim] userChaincodeStreamGetter -> ERRO 003 Error trying to connect to local peer: context deadline exceeded

07-在开发者模式下调试chaincode

但是在电脑上的 Ubuntu 上启动 ChainCode,一切正常。到现在我都不理解这是为什么!!!只能理解为玄学级别的 Bug 了(生无可恋脸)。

总结

这篇文章主要是根据官方文档加上自己的理解整理而成。关于玄学级 Bug,目前还没有发现解决的办法。今后若是发现了,再回来填坑~

参考链接:

HyperLedger-Fabric 文档-ChainCode 开发手册hyperledger-fabric.readthedocs.io

转自知乎 苏小乐 :https://www.zhihu.com/people/shan-de-ding-zhu/activities

露水湾 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:07-在开发者模式下调试chaincode
喜欢 (0)
[]
分享 (0)
关于作者:
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址