说明:链码开发语言是golang,源码分析是基于v1.4.3版本
Peer节点支持扩展插件,以满足不同的业务需求。
相关配置在core.yaml文件中,配置项为peer.handlers,共支持4类扩展插件:
a) authFilters,用于拒绝或转发client的提案;
b) decorators,用于附加或修改peer传递给链码的参数;
c) endorsers,自定义的背书实现,可以修改背书的格式,扩展内容等;
d) validators,自定义的交易校验实现,可以修改校验的方式,扩展校验的内容等;
系列文章:
1、Fabric自定义插件的开发-Decorator插件开发
2、Fabric自定义插件的开发-Validators插件开发
3、Fabric自定义插件的开发-Auth插件开发
插件的原理关注之前的文章《fabric系统链码插件开发总结》
peer启动之后,根据配置文件,构造插件相关的library.Config对象,并初始化插件库:
相关代码如下:
函数:func serve(args []string) error {}
位置:peer/node/start.go:129
函数:func InitRegistry(c Config) Registry {}
位置:core/handlers/library/registry.go:80
函数:func (r *registry) loadHandlers(c Config) {}
位置:core/handlers/library/registry.go:92
函数:func (r *registry) evaluateModeAndLoad(c *HandlerConfig, handlerType HandlerType, extraArgs ...string) {}
位置:core/handlers/library/registry.go:110
library.Config对象定义如下:
type Config struct {
AuthFilters []*HandlerConfig `mapstructure:"authFilters" yaml:"authFilters"`
Decorators []*HandlerConfig `mapstructure:"decorators" yaml:"decorators"`
Endorsers PluginMapping `mapstructure:"endorsers" yaml:"endorsers"`
Validators PluginMapping `mapstructure:"validators" yaml:"validators"`
}
可见,AuthFilters和Decorators是Slice结构,而Endorsers和Validators是map结构。
在Peer中维护的插件库是一个单例,内部对象是:core/handlers/library.registry,实现了Lookup(HandlerType) interface{}方法获取对应的Handler,定义如下:
type registry struct {
filters []auth.Filter
decorators []decoration.Decorator
endorsers map[string]endorsement2.PluginFactory
validators map[string]validation.PluginFactory
}
所有成员最终都是接口类型对象,方便扩展,只需要实现接口即可。而endorsers和validators需要指定key,这样支持给不同的链码指定不同的扩展插件。通过链码实例化或升级时的-E和-V参数来指定。
加载的核心代码:
函数:func (r *registry) loadPlugin(pluginPath string, handlerType HandlerType, extraArgs ...string) {}
位置:core/handlers/library/registry.go:147
函数:func (r *registry) loadCompiled(handlerFactory string, handlerType HandlerType, extraArgs ...string) {}
位置:core/handlers/library/registry.go:119
插件的定义:
type HandlerConfig struct {
Name string `mapstructure:"name" yaml:"name"`
Library string `mapstructure:"library" yaml:"library"`
}
根据Library是否为空,来决定使用哪种加载方式。
相关代码如下:
func (r *registry) initAuthPlugin(p *plugin.Plugin) {}
func (r *registry) initDecoratorPlugin(p *plugin.Plugin) {}
func (r *registry) initEndorsementPlugin(p *plugin.Plugin, extraArgs ...string) {}
func (r *registry) initValidationPlugin(p *plugin.Plugin, extraArgs ...string) {}
其实就是使用fabric的默认实现,相关代码如下:
func (r *HandlerLibrary) DefaultAuth() auth.Filter {}
func (r *HandlerLibrary) ExpirationCheck() auth.Filter {}
func (r *HandlerLibrary) DefaultDecorator() decoration.Decorator {}
func (r *HandlerLibrary) DefaultEndorsement() endorsement.PluginFactory {}
func (r *HandlerLibrary) DefaultValidation() validation.PluginFactory {}
一般,自定义的扩展插件都是使用Library方式指定,这样可以不修改fabric的源码,也不需要重新编译peer,直接使用官方镜像即可。
插件方式加载的具体实现后续梳理并举例实现~