超级账本源码分析(十一) - peer的System Chaincode

System Chaincode

以下文字翻译自 Fabric 文档中关于系统链码(System Chaincode)的部分。
系统链码与一般chaincode一样,有相同的编程模型,比不过系统链码是运行在peer程序中,即其是peer程序的一部分,而一般的chaincode是单独运行在一个容器中的。因此,系统链码是内建在peer程序中且不遵循一般chaincode那样的生命周期。特别的,install,instantiate和upgrade操作也不应用于系统链码。

系统链码区别与一般的chaincode的目的是缩短grpc在peer结点与chaincode之间通信的时间消耗(因为peer结点在一个容器,chaincode是单独的一个容器),并权衡管理上的灵活性。比如,一个系统链码可以仅通过升级peer程序的二进制包来得到升级。系统链码可以用预定义的元素注册并编译到peer程序中,而且不需要有类似于背书策略或背书功能等这样的冗杂的功能。

系统链码被用在fabric中,去操纵整个系统的配置表现,这样的话可以随时把系统改变到合适的状态。

当前存在的系统链码名单:

  • LSCC Lifecycle system chaincode,处理生命周期请求。我理解的生命周期请求应该指的是一个chaincode的安装,实例化,升级,卸载等对其生命周期起关键作用的一系列操作请求。
  • CSCC Configuration system chaincode,处理在peer程序端的频道配置。
  • QSCC Query system chaincode,提供账本查询接口,如获取块和交易信息。
  • ESCC Endorsement system chaincode,通过对交易申请的应答信息进行签名,来提供背书功能。
  • VSCC Validation system chaincode,处理交易校验,包括检查背书策略和版本在并发时的控制。

在修改或替换系统链码时必须注意,特别是LSCC,ESCC和VSCC,因为它们处于重要的交易环节中。以vscc为例,因为区块链中的交易数据都是持久性的,因此当vscc在提交一个block到账本中之前要先验证该区块,这不值什么,重要的是在同频道中的所有peer必须计算出相同的证书(由验证输出的证书)以避免账本产生冲突。因此特别需要注意的是vscc被修改或替换时,要避免和以前所产生的交易数据产生冲突。

简介

System Chaincode即系统链码。
在 /peer/node/start.go 中的registerChaincodeSupport()函数实现了注册 System Chaincode:

	//Now that chaincode is initialized, register all system chaincodes.
	sccs := scc.CreateSysCCs(ccp, sccp, aclProvider)
	for _, cc := range sccs {
		sccp.RegisterSysCC(cc)
	}

系统链码的核心代码在/fabric/core/common/sysccprovider和/fabric/core/scc下,scc也就是System Chaincode的缩写。
系统链码分为五种:cscc,escc,lscc,qscc,vscc,均为各个系统链码的缩写。系统链码均实现了/fabric/core/chaincode/shim/interfaces.go中定义的Chaincode接口,从此点就可以看出,系统链码也属于Chaincode,只不过作用稍微特殊一点,

// Chaincode interface must be implemented by all chaincodes. The fabric runs
// the transactions by calling these functions as specified.
type Chaincode interface {
	// Init is called during Instantiate transaction after the chaincode container
	// has been established for the first time, allowing the chaincode to
	// initialize its internal data
	Init(stub ChaincodeStubInterface) pb.Response

	// Invoke is called to update or query the ledger in a proposal transaction.
	// Updated state variables are not committed to the ledger until the
	// transaction is committed.
	Invoke(stub ChaincodeStubInterface) pb.Response
}

五种系统链码的全称:

  • cscc:configuration system chaincode
  • lscc:lifecycle system chaincode
  • escc:endorser system chaincode
  • vscc:validator system chaincode
  • qscc:querier system chaincode

/fabric/core/common/sysccprovider目录下的文件有:

  • sysccprovider.go - 定义系统链码服务提供者接口

/fabric/core/scc 目录下有:

  • sysccapi.go - 系统链码的各种api操作
  • importsysccs.go - 导入五种预定义的系统链码
  • sccproviderimpl.go - 定义了系统链码服务提供者的具体实现和其操作

系统链码的创建和注册

在fabric/peer/node/start.go中的registerChaincodeSupport()函数中:

	//Now that chaincode is initialized, register all system chaincodes.
	sccs := scc.CreateSysCCs(ccp, sccp, aclProvider)
	for _, cc := range sccs {
		sccp.RegisterSysCC(cc)
	}

先调用scc.CreateSysCCs()创建所有系统链码,看下scc.CreateSysCCs()方法,最终会调用importsysccs.go的
builtInSystemChaincodes()方法:

func builtInSystemChaincodes(ccp ccprovider.ChaincodeProvider, p *Provider, aclProvider aclmgmt.ACLProvider) []*SystemChaincode {
	return []*SystemChaincode{
		{
			Enabled:           true,
			Name:              "cscc",
			Path:              "github.com/hyperledger/fabric/core/scc/cscc",
			InitArgs:          nil,
			Chaincode:         cscc.New(ccp, p, aclProvider),
			InvokableExternal: true, // cscc is invoked to join a channel
		},
		{
			Enabled:           true,
			Name:              "lscc",
			Path:              "github.com/hyperledger/fabric/core/scc/lscc",
			InitArgs:          nil,
			Chaincode:         lscc.New(p, aclProvider),
			InvokableExternal: true, // lscc is invoked to deploy new chaincodes
			InvokableCC2CC:    true, // lscc can be invoked by other chaincodes
		},
		{
			Enabled:           true,
			Name:              "qscc",
			Path:              "github.com/hyperledger/fabric/core/scc/qscc",
			InitArgs:          nil,
			Chaincode:         qscc.New(aclProvider),
			InvokableExternal: true, // qscc can be invoked to retrieve blocks
			InvokableCC2CC:    true, // qscc can be invoked to retrieve blocks also by a cc
		},
	}
}

系统链码创建完成后调用sccp.RegisterSysCC(cc)进行注册,sccp.RegisterSysCC(cc)定义在fabric/core/scc/sccproviderimpl.go中:

// RegisterSysCC registers a system chaincode with the syscc provider.
func (p *Provider) RegisterSysCC(scc *SystemChaincode) {
	p.SysCCs = append(p.SysCCs, scc)
	_, err := p.registerSysCC(scc)
	if err != nil {
		sysccLogger.Panic("Could not register system chaincode: %s", err)
	}
}

然后会调用/fabric/core/scc/sysccapi.go中的registerSysCC()方法:

// registerSysCC registers the given system chaincode with the peer
func (p *Provider) registerSysCC(syscc *SystemChaincode) (bool, error) {
	if !syscc.Enabled || !syscc.isWhitelisted() {
		sysccLogger.Info(fmt.Sprintf("system chaincode (%s,%s,%t) disabled", syscc.Name, syscc.Path, syscc.Enabled))
		return false, nil
	}

	// XXX This is an ugly hack, version should be tied to the chaincode instance, not he peer binary
	version := util.GetSysCCVersion()

	ccid := &ccintf.CCID{
		Name:    syscc.Name,
		Version: version,
	}
	err := p.Registrar.Register(ccid, syscc.Chaincode)
	if err != nil {
		//if the type is registered, the instance may not be... keep going
		if _, ok := err.(inproccontroller.SysCCRegisteredErr); !ok {
			errStr := fmt.Sprintf("could not register (%s,%v): %s", syscc.Path, syscc, err)
			sysccLogger.Error(errStr)
			return false, fmt.Errorf(errStr)
		}
	}

	sysccLogger.Infof("system chaincode %s(%s) registered", syscc.Name, syscc.Path)
	return true, err
}

最终调用p.Registrar.Register(ccid, syscc.Chaincode)方法进行注册,定义在/fabric/core/container/inproccontroller/inproccontroller.go中:

//Register registers system chaincode with given path. The deploy should be called to initialize
func (r *Registry) Register(ccid *ccintf.CCID, cc shim.Chaincode) error {
	name := ccid.GetName()
	inprocLogger.Debugf("Registering chaincode instance: %s", name)
	tmp := r.typeRegistry[name]
	if tmp != nil {
		return SysCCRegisteredErr(name)
	}

	r.typeRegistry[name] = &inprocContainer{chaincode: cc}
	return nil
}

Register()函数以系统链码path成员值为key,包含系统链码的inprocContainer对象为value,将系统链码放入typeRegistry映射中。至此,系统链码注册完毕。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值