小言_互联网的博客

fabric系统链码插件开发总结

245人阅读  评论(0)

声明:链码开发语言是golang,源码分析是基于v1.4.3版本

Hyperledger Fabric有一个很好的特性,就是有很多特性是可插拔的,可以很方便的进行自定义扩展,以契合具体的业务场景。今天分享如何使用系统链码插件。

系统链码可插拔的实现原理

基于Golang的Plugin特性

Golang在1.8版本时已经支持了Plugin特性,但是只支持Linux和macOS。
Plugin的优势在于轻量以及弱耦合:
    1、轻量:运行空间就是主进程,无需额外支持通信相关功能;
    2、弱耦合:接口定义完毕之后,插件可独立开发,独立升级,对主进程无影响;
Plugin的底层实现也极简单,核心只有一个结构体和一个接口:

type Plugin struct {
	pluginpath string
	err        string        // set if plugin failed to load
	loaded     chan struct{} // closed when loaded
	syms       map[string]interface{}
}
func Open(path string) (*Plugin, error) {}
func (p *Plugin) Lookup(symName string) (Symbol, error) {}
type Symbol interface{}

使用Open函数来加载一个插件,通过Lookup找到插件中对应的变量或者函数,以Symbol返回,再通过Go的类型断言取到原本的变量或者函数即可进行访问。

插件的代码必须在一个main包中。

Fabirc相关设计

peer 启动后读取core.yaml文件中chaincode.systemPlugins配置项,获取系统链码插件定义,可定义多个系统链码插件,相关结构如下:

type PluginConfig struct {
	Enabled           bool   `mapstructure:"enabled" yaml:"enabled"`
	Name              string `mapstructure:"name" yaml:"name"`
	Path              string `mapstructure:"path" yaml:"path"`
	InvokableExternal bool   `mapstructure:"invokableExternal" yaml:"invokableExternal"`
	InvokableCC2CC    bool   `mapstructure:"invokableCC2CC" yaml:"invokableCC2CC"`
}
其中:
    a)、Enabled表示是否启用该系统链码插件
    b)、Name表现系统链码名
    c)、Path表示链码链码插件在磁盘上的绝对路径
    d)、InvokableExternal和InvokableCC2CC分别表示该系统链码是否允许外部直接调用、是否允许通过链码调用

加载每一个系统链码插件(plugin.Open),查找名称为New,类型为func() shim.Chaincode的函数并调用,以创建链码对象,该对象应实现接口github.com/hyperledger/fabric/core/chaincode/shim.Chaincode
相关函数:

函数: func CreatePluginSysCCs(p *Provider) []SelfDescribingSysCC {}
位置: core/scc/register_pluginsenabled.go:13
函数: func loadSysCCs(p *Provider) []*SystemChaincode {}
位置: core/scc/loadsysccs.go:37
函数: func loadPlugin(path string) *shim.Chaincode {}
位置: core/scc/loadsysccs.go:65
系统链码白名单校验函数:func isWhitelisted(syscc SelfDescribingSysCC) bool {
位置: core/scc/sysccapi.go:206

使用系统链码插件,需要配置系统链码白名单,在core.yaml中chaincode.system中配置。

系统链码插件开发与使用

插件开发

系统链码插件的开发,可以fabric的源码中的样例:$GOPATH/src/github.com/hyperledger/fabric/examples/plugins/scc/plugin.go
简单说一下,满足以下约束:
    1、必须定义一个结构体,实现github.com/hyperledger/fabric/core/chaincode/shim.Chaincode接口
    2、必须定义并实现一个func New() shim.Chaincode格式函数,一般就是返回1中定义的结构体实例

编译peer容器

因为Hyperledger Fabric官方的peer镜像并不支持系统链码的可插拔特性,因此需要自行编译peer容器。而官方Makefile和peer的Dockerfile并不会把我们的插件集成进去,因此需要进行定制:
step 1:打开编译选项,使peer支持系统链码插件:export set GO_TAGS=pluginsenabled
step 2:设置环境变量,export set DOCKER_DYNAMIC_LINK=true
step 3:checkout Fabric的源码,并把系统链码放置在$GOPATH/src/github.com/hyperledger/fabric/myscc目录下
step 4:修改$GOPATH/src/github.com/hyperledger/fabric/Makefile文件:

增加编译系统链码的规则:
$(BUILD_DIR)/docker/bin/myscc.so:
	$(eval TARGET = ${patsubst $(BUILD_DIR)/docker/bin/%,%,${@}})
	@echo "Building $@"
	@$(DRUN) \
		-v $(abspath $(BUILD_DIR)/docker/bin):/opt/gopath/bin \
		$(BASE_DOCKER_NS)/fabric-baseimage:$(BASE_DOCKER_TAG) \
		go build --buildmode=plugin -tags "$(GO_TAGS)" -o /opt/gopath/bin/myscc.so ./myscc/ $(pkgmap.$(@F))
修改$(BUILD_DIR)/image/peer/payload规则:
$(BUILD_DIR)/image/peer/payload:       $(BUILD_DIR)/docker/bin/peer \
				$(BUILD_DIR)/sampleconfig.tar.bz2 \
				$(BUILD_DIR)/docker/bin/myscc.so

Makefile的不能有空格,需要使用Tab键
step 5:修改peer镜像的$GOPATH/src/github.com/hyperledger/fabric/image/peer/payload/Dockerfile.in文件,创建/opt/lib目录,并将插件拷贝到该目录下:

# Copyright Greg Haskins All Rights Reserved
#
# SPDX-License-Identifier: Apache-2.0
#
FROM _BASE_NS_/fabric-baseos:_BASE_TAG_
ENV FABRIC_CFG_PATH /etc/hyperledger/fabric
RUN mkdir -p /opt/lib /var/hyperledger/production $FABRIC_CFG_PATH
COPY payload/peer /usr/local/bin
COPY payload/myscc.so /opt/lib/
ADD  payload/sampleconfig.tar.bz2 $FABRIC_CFG_PATH
CMD ["peer","node","start"]

step 6:在$GOPATH/src/github.com/hyperledger/fabric目录下执行:make peer-docker即可生成定制的peer镜像。

测试

执行:docker run hyperledger/fabric-peer:amd64-1.4.4-snapshot-e09c726
日志:
    2019-09-24 10:14:14.259 UTC [sccapi] deploySysCC -> INFO 01e system chaincode myscc/(/opt/lib/myscc.so) deployed


转载:https://blog.csdn.net/huchenguang/article/details/101286653
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场