Fabric自定义插件的开发-Validators插件开发

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

系列文章
1、Fabric自定义插件的开发-扩展插件的组织方式
2、Fabric自定义插件的开发-Decorator插件开发
3、Fabric自定义插件的开发-Auth插件开发

validators插件,其实就是系统链码里的vscc链码,用于校验区块中交易的背书是否满足背书策略。如果需要定制校验逻辑,或者在默认校验逻辑上增加新的校验,就需要开发validdators插件了。本文梳理validators插件的加载和使用方式,以及分享一个样例。

插件加载

读取插件,在自定义的插件中查找NewPluginFactory函数,且函数格式为:func() validation.PluginFactory,即需要返回一个实现了接口core.handlers.validation.PluginFactory的对象,并将该对象存储在插件库对象registry的成员validators中,注意这里的validators是map结构,其key来自配置文件core.yaml。
这里相比Decorator插件,多了一层,因为Decorator插件是单例,而Validators插件是多实例,每个通道都会有一个实例。
core.handlers.validation.PluginFactory接口定义如下:

type PluginFactory interface {
	New() Plugin
}

New方法返回的是一个实现Plugin接口的对象,Plugin接口定义如下:

type Plugin interface {
	Validate(block *common.Block, namespace string, txPosition int, actionPosition int, contextData ...ContextDatum) error
	Init(dependencies ...Dependency) error
}

这个实现了Plugin接口的对象,才是我们自定义validators插件中的核心对象!

插件使用
peer如何使用插件

同样是通过peer的插件库单例registry对象提供的Lookup方法。peer在创建chain对象时,就把所有validators插件定义和chain对象进行关联。

txvaliddator.PluginMapper接口对象
函数:func createChain(cid string, ledger ledger.PeerLedger, cb *common.Block, ccp ccprovider.ChaincodeProvider, sccp sysccprovider.SystemChaincodeProvider, pm txvalidator.PluginMapper) error {}
位置:core/peer/peer.go:328

peer在收到新的区块之后,解析区块中的交易,获取交易对应的channelId、chaincodeId,从db中读取chaincodeid对应的信息,如背书策略、vscc名称、escc名称等信息;如果是系统链码,背书策略为通道内任意组织背书,vscc和escc都是默认系统链码。

函数:func (v *VsccValidatorImpl) VSCCValidateTx(seq int, payload *common.Payload, envBytes []byte, block *common.Block) (error, peer.TxValidationCode) {}
位置:core/committer/txvalidator/vscc_validator.go:49
// 从db中获取链码对应的信息
函数:func (v *VsccValidatorImpl) GetInfoForValidate(chdr *common.ChannelHeader, ccID string) (*sysccprovider.ChaincodeInstance, *sysccprovider.ChaincodeInstance, []byte, error) {} 
位置:core/committer/txvalidator/vscc_validator.go:325

在获取链码信息之后,根据vscc的名称获取指定的validators插件对象(实现了Plugin接口的对象),缓存并调用Validate方法。

函数:func (pv *PluginValidator) ValidateWithPlugin(ctx *Context) error {}
位置:core/committer/txvalidator/plugin_validator.go:92
函数:func (pv *PluginValidator) getOrCreatePlugin(ctx *Context) (validation.Plugin, error) {}
位置:core/committer/txvalidator/plugin_validator.go:108
// 新创建的插件对象,会调用Init方法
函数:func (pbc *pluginsByChannel) createPluginIfAbsent(channel string) (validation.Plugin, error) {}
位置:core/committer/txvalidator/plugin_validator.go:144

vscc对应的默认实现是:
对象:core.handlers.validation.builtin.DefaultValidation
位置:core/handlers/validation/builtin/default_validation.go:35

如何配置插件

1、修改core.yaml文件,增加自定义validators的信息:

validators:
    vscc:
        name: DefaultValidation
        library:
    customvscc:
      	library: /opt/lib/xxx.so

2、在链码实例化或升级的时候,通过-V参数指定链码使用的vscc名称,如:
peer chaincode instantiate -o orderer.example.com:7050 -n yourchaincode -v 1.0 -V customvscc -C yourchannel -c ‘{“Args”:[“init”,“a”,“1”]}’ -P “OR (‘Org1MSP.member’,‘Org2MSP.member’,‘Org3MSP.member’)”

插件开发样例

样例没有特殊功能,只是复用了vscc的默认实现。

package main

import (
	validation "github.com/hyperledger/fabric/core/handlers/validation/api"
	"github.com/hyperledger/fabric/core/handlers/validation/builtin"
	"github.com/hyperledger/fabric/protos/common"
)

// 函数签名不可修改,名称必须是NewPluginFactory,类型必须是func() validation.PluginFactory
func NewPluginFactory() validation.PluginFactory { 
	return &ValidateFactory{}
}

type ValidateFactory struct {
}

func (*ValidateFactory) New() validation.Plugin {
	return &ipfsValidation{
		defValidate: &builtin.DefaultValidation{},
	}
}

type ipfsValidation struct {
	defValidate *builtin.DefaultValidation
}

func (v *ipfsValidation) Validate(block *common.Block, namespace string, txPosition int, actionPosition int, contextData ...validation.ContextDatum) error {
	// 修改这个函数的实现即可
	resp := v.defValidate.Validate(block, namespace, txPosition, actionPosition, contextData...)
	if resp != nil {
		return resp
	}

	return nil
}

func (v *ipfsValidation) Init(dependencies ...validation.Dependency) error {
	return v.defValidate.Init(dependencies...)
}

func main() {
}

插件的编译使用命令 go build -buildmod=plugin,生成so。
因为有依赖fabric源码,所以编译时,需要先clone一份fabric的代码,且在fabric的目录下进行编译,这样就可以直接用fabric项目的vendor了
这里有个限制,如果你的peer是1.4.0版本,那么在编译so时,也必须使用相同版本的fabric源码,否则会导致so加载失败!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值