在我的一篇文章中,介绍了超级账本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
,但是有下面几点要注意:
应用本国密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
是没有问题的。这里我们缺省使用默认设置就行。
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
中的源码来解决。这个放到后面用到时再讲。
配置文件中所有和路径相关的/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
下载完成后在原终端接着运行程序,这里根据不同的操作系统会有不同的结果:
运行成功,从输出日志我们可以看到链码中a的值是正确的。
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
,就会成功。
因为Mac下配置文件中的systemCertPool
为true
,在国密版本中会找到不对应的文件而初始化为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了。因此,本文绝大部分内容是凭记忆写成的,没有写一步实际对照操作一步。如果中间有遗漏或者错误,欢迎大家留言指正或者讨论。