一个基于同济技术路线实现的Fabric超级账本国密fabric-sdk-go的应用流程

在我的一篇文章中,介绍了超级账本Fabric v1.4.1国密版本的部署测试流程,但是那篇文章测试Fabric时使用的是CLI。我们知道,一个完整的Fabric超级账本的国密改造包括Fabric 源码、Fabric SDK和 Fabric CA这三个部分的国密改造。其中Fabric CA的需求紧迫性不是很高,但Fabric SDK的国密改造需求是真真切切的,没有它就没有办法写程序与Fabric交互。因此,本文以网上开源的一个fabric-sdk-go-gm版本为例,以Fabric v1.4.1(v1.4.6也行)国密改造版本为底层联盟链,简单介绍一下国密fabric-sdk-go的使用流程。

一、准备工作

1、参考我的那篇文章Fabric 超级账本 1.4.1国密改造版本Centos单机部署及测试流程 在本机部署一个国密版本的Fabric。部署完成后进入first-network目录使用./byfn.sh up启动一个测试网络。虽然那篇文章讲的是在Centos环境的操作,但是Mac OS和Windows下也是可行的。
2、下载bolenzhang开源一个go-sdk,下载后的目录没有要求,可以放在$GOPATH/src/github.com/hyperledger目录下,和Fabric放在一起。

cd $GOPATH/src/github.com/hyperledger/
git clone [email protected]:bolenzhang/fabric-go-sdk-gm.git

3、运行go env检查GO111MODULE环境变量是否为auto。不是要改过来并使之生效(windows下要多检查几次是否生效了,有可能要注销或者重启)

二、新建一个应用工程

我们使用了国密版本的go-sdk,不能直接使用go mod来管理依赖。所有依赖需要放置在vendor目录下,但是我们可以首先使用go mod来下载依赖库。

cd $GOPATH/src
mkdir sdk_test
cd sdk_test
go mod init sdktest

三、建立配置文件

直接引用使用fabric-sdk-go操作链码这篇文章中给出的示例SDK配置文件config.yaml,保存为sdk_test/config.yaml,但是有下面几点要注意:

3.1、BCCSP

应用本国密go-sdk时,此项应该注释掉。

  # [Optional] BCCSP config for the client. Used by GO SDK.
  # BCCSP:
  #   security:
  #     enabled: true
  #     default:
  #       provider: "GM"
  #     hashAlgorithm: "GMSM3"
  #     softVerify: true
  #     level: 256

因为该SDK会自动对算法进行转换,我们不需要设置为GM。当然你按原配置文件设置为SW是没有问题的。这里我们缺省使用默认设置就行。

3.2、tlsCerts

  tlsCerts:
    # [Optional]. Use system certificate pool when connecting to peers, orderers (for negotiating TLS) Default: false
    systemCertPool: true

如果你是Windows操作系统,这里要改成false,注意冒号和后面的"true"是有个空格的。如果你是Centos或者Ubuntu等系统,可以不用改;如果你是Mac操作系统,这里不改会有一点问题,但是我们可以修改一下sm2中的源码来解决。这个放到后面用到时再讲。

3.3、所有路径

配置文件中所有和路径相关的/Users/shitaibin/go/src/github.com/hyperledger/fabric/fabric-samples都要替换成你本地的真实路径,注意windows下没有/,估计应该使用\\(这一点不太确定)。

四、编写测试文件

本文以一个简单的main.go作为测试文件,该测试文件的写法同样参考上面提到的那篇《使用fabric-sdk-go操作链码》文章。使用你的编辑器或者vim在项目根目录建立一个main.go,内容如下:

package main

import (
	"fmt"
	"log"
	"time"

	"github.com/hyperledger/fabric-sdk-go/pkg/client/channel"
	"github.com/hyperledger/fabric-sdk-go/pkg/core/config"
	"github.com/hyperledger/fabric-sdk-go/pkg/fabsdk"
)

const (
	org1CfgPath = "./config.yaml"
	ChannelID   = "mychannel"

	peer0Org1 = "peer0.org1.example.com"
	peer0Org2 = "peer0.org2.example.com"
)

func main() {
	sdk, err := fabsdk.New(config.FromFile(org1CfgPath))
	if err != nil {
		log.Panicf("failed to create fabric sdk: %s", err)
	}

	ccp := sdk.ChannelContext(ChannelID, fabsdk.WithUser("User1"))
	cc, err := channel.New(ccp)
	if err != nil {
		log.Panicf("failed to create channel client: %s", err)
	}

	query(cc)
	execute(cc)
	time.Sleep(5 * time.Second)
	query(cc)
}

func query(cc *channel.Client) {
	// new channel request for query
	req := channel.Request{
		ChaincodeID: "mycc",
		Fcn:         "query",
		Args:        packArgs([]string{"a"}),
	}
	// send request and handle response
	reqPeers := channel.WithTargetEndpoints(peer0Org1)

	response, err := cc.Query(req, reqPeers)
	if err != nil {
		fmt.Printf("failed to query chaincode: %s\n", err)
	}

	if len(response.Payload) > 0 {
		fmt.Printf("chaincode query success,the value is %s\n", string(response.Payload))
	}
}

func execute(cc *channel.Client) {
	args := packArgs([]string{"a", "b", "10"})
	req := channel.Request{
		ChaincodeID: "mycc",
		Fcn:         "invoke",
		Args:        args,
	}
	peers := []string{peer0Org1, peer0Org2}
	reqPeers := channel.WithTargetEndpoints(peers...)
	response, err := cc.Execute(req, reqPeers)
	if err != nil {
		fmt.Printf("failed to Execute chaincode: %s\n", err)
	}
	fmt.Printf("Execute chaincode success,txId:%s\n", response.TransactionID)
}

func packArgs(paras []string) [][]byte {
	var args [][]byte
	for _, k := range paras {
		args = append(args, []byte(k))
	}
	return args
}

该测试文件很简单,先是初始化SDK和建立通道,然后查询合约,执行交易,然后再查询合约看值有无更新。

五、安装依赖

重点来了:这里操作比较多,我们假定你在项目根目录sdk_test下操作,并且国密版本的SDK也按照建议放置在$GOPATH/src/github.com/hyperledger/目录下:

go run main.go

会先安装依赖,然后报错解析x509证书出错,不理它,正常结果。
接着执行:

go mod vendor

将所有依赖复制到工程的vendor目录下。
接着执行:

rm go.mod
rm go.sum
rm -rf vendor/github.com/hyperledger/fabric-sdk-go
cp -r $GOPATH/src/github.com/hyperledger/fabric-go-sdk-gm vendor/github.com/hyperledger/fabric-sdk-go

上面命令的含义是删除go mod的相关内容,并且使用国密SDK来替换原生SDK。

六、运行测试

让我们再次运行go run main.go,如果提示缺少一些库,可以新开一个终端,参考下面的命令来下载:

mkdir -p $GOPATH/src/golang.org/x
cd $GOPATH/src/golang.org/x
git clone https://github.com/golang/crypto.git

下载完成后在原终端接着运行程序,这里根据不同的操作系统会有不同的结果:

1、Centos或者Ubuntu

运行成功,从输出日志我们可以看到链码中a的值是正确的。

2、windows

windows环境下的运行会报错(注意,windows下配置文件中的systemCertPool要为false):

# chaincodedemo/vendor/github.com/google/certificate-transparency-go/x509
vendor\github.com\google\certificate-transparency-go\x509\root_windows.go:112:3: cannot use uintptr(unsafe.Pointer(sslPara)) (type uintptr) as type syscall.Pointer in field value

这是因为有个库太老了, 我们需要手动更新一下。

git clone [email protected]:google/certificate-transparency-go.git

将下载后的库复制到vendor对应的目录中去进行替代。再次运行go run main.go,就会成功。

3、Mac OS

因为Mac下配置文件中的systemCertPooltrue,在国密版本中会找到不对应的文件而初始化为nil,从而报错。经过测试,原版Fabric配合原版fabric-sdk-go不会有这个问题。这个问题是因为在sm2/cert_pool.go文件中,没有列出Mac OS下可能的文件位置。根据报错信息,我们打开vendor/github.com/fabric-sdk-go/internal/github.com/tjfoc/gmsm/sm2/cert_pool.go (推荐使用vscode)打开,可以看到有这么两段定义:

// Possible certificate files; stop after finding one.
var certFiles = []string{
	"/etc/ssl/certs/ca-certificates.crt",                // Debian/Ubuntu/Gentoo etc.
	"/etc/pki/tls/certs/ca-bundle.crt",                  // Fedora/RHEL 6
	"/etc/ssl/ca-bundle.pem",                            // OpenSUSE
	"/etc/pki/tls/cacert.pem",                           // OpenELEC
	"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
}

// Possible directories with certificate files; stop after successfully
// reading at least one file from a directory.
var certDirectories = []string{
	"/etc/ssl/certs",               // SLES10/SLES11, https://golang.org/issue/12139
	"/system/etc/security/cacerts", // Android
}

程序就是在上面列出的文件或者路径中初始化系统证书池的。

Mac OS虽然存在"/etc/ssl/certs"目录,但里面为空。因此,google了一下后,需要在certFiles中增加一个Mac OS下的定义"/usr/local/etc/openssl/cert.pem", // Mac从而改为:

// Possible certificate files; stop after finding one.
var certFiles = []string{
	"/etc/ssl/certs/ca-certificates.crt",                // Debian/Ubuntu/Gentoo etc.
	"/etc/pki/tls/certs/ca-bundle.crt",                  // Fedora/RHEL 6
	"/etc/ssl/ca-bundle.pem",                            // OpenSUSE
	"/etc/pki/tls/cacert.pem",                           // OpenELEC
	"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
	"/usr/local/etc/openssl/cert.pem",                   // Mac
}

保存退出,然后再次运行go run main.go,就会正确的输出a的值了。

七、总结

好了,从本文来看,国密fabric-sdk-go配合国密Fabric的测试还是挺简单的(主要就是go-sdk的应用,国密sdk别人写好了)。这里非常感谢bolenzhang放出来的国密fabric-go-sdk-gm仓库。用到的读者可以在github上给他点个star哟。

到目前为止,Fabric超级账本的国密改造基于网上开源版本的应用目前就只差一个Fabric CA了。这个CA等找到合适的开源国密版本后我再写一篇文章介绍其用法。

为了测试CA,我的本地环境已经改成原版Fabric了。因此,本文绝大部分内容是凭记忆写成的,没有写一步实际对照操作一步。如果中间有遗漏或者错误,欢迎大家留言指正或者讨论。

你可能感兴趣的:(Fabric,超级账本)