您现在的位置是:首页 > 文章详情

区块链教程Fabric1.0源代码分析Chaincode(链码)体系总结-兄弟连

日期:2018-10-28点击:289

Fabric 1.0源代码笔记 之 Chaincode(链码)

1、Chaincode概述

Chaincode,即链码或智能合约,代码分布在protos/peer目录、core/chaincode和core/common/ccprovider目录,目录结构如下:

  • protos/peer目录:
        * chaincode.pb.go,ChaincodeDeploymentSpec、ChaincodeInvocationSpec结构体定义。
  • core/chaincode目录:
        * platforms目录,链码的编写语言平台实现,如golang或java。

        * platforms.go,Platform接口定义,及部分工具函数。
        * java目录,java语言平台实现。
        * golang目录,golang语言平台实现。

  • core/common/ccprovider目录:ccprovider相关实现。

2、protos相关结构体定义

2.1、ChaincodeDeploymentSpec结构体定义(用于Chaincode部署)

2.1.1 ChaincodeDeploymentSpec结构体定义

type ChaincodeDeploymentSpec struct {     ChaincodeSpec *ChaincodeSpec //ChaincodeSpec消息     EffectiveDate *google_protobuf1.Timestamp     CodePackage []byte //链码文件打包     ExecEnv ChaincodeDeploymentSpec_ExecutionEnvironment //链码执行环境,DOCKER或SYSTEM } type ChaincodeDeploymentSpec_ExecutionEnvironment int32 const (     ChaincodeDeploymentSpec_DOCKER ChaincodeDeploymentSpec_ExecutionEnvironment = 0     ChaincodeDeploymentSpec_SYSTEM ChaincodeDeploymentSpec_ExecutionEnvironment = 1 ) //代码在protos/peer/chaincode.pb.go

2.1.2、ChaincodeSpec结构体定义

type ChaincodeSpec struct {     Type ChaincodeSpec_Type //链码的编写语言,GOLANG、JAVA     ChaincodeId *ChaincodeID //ChaincodeId,链码路径、链码名称、链码版本     Input *ChaincodeInput //链码的具体执行参数信息     Timeout int32 } type ChaincodeSpec_Type int32 const (     ChaincodeSpec_UNDEFINED ChaincodeSpec_Type = 0     ChaincodeSpec_GOLANG ChaincodeSpec_Type = 1     ChaincodeSpec_NODE ChaincodeSpec_Type = 2     ChaincodeSpec_CAR ChaincodeSpec_Type = 3     ChaincodeSpec_JAVA ChaincodeSpec_Type = 4 ) type ChaincodeID struct {     Path string     Name string     Version string } type ChaincodeInput struct { //链码的具体执行参数信息     Args [][]byte } //代码在protos/peer/chaincode.pb.go

2.2、ChaincodeInvocationSpec结构体定义

type ChaincodeInvocationSpec struct {     ChaincodeSpec *ChaincodeSpec //参考本文2.2     IdGenerationAlg string } //代码在protos/peer/chaincode.pb.go

3、ccprovider目录相关实现

3.1、ChaincodeData结构体

type ChaincodeData struct {     Name string     Version string     Escc string     Vscc string     Policy []byte //chaincode 实例的背书策略     Data []byte     Id []byte     InstantiationPolicy []byte //实例化策略 } //获取ChaincodeData,优先从缓存中读取 func GetChaincodeData(ccname string, ccversion string) (*ChaincodeData, error) //代码在core/common/ccprovider/ccprovider.go

func GetChaincodeData(ccname string, ccversion string) (*ChaincodeData, error)代码如下:

var ccInfoFSProvider = &CCInfoFSImpl{} var ccInfoCache = NewCCInfoCache(ccInfoFSProvider) func GetChaincodeData(ccname string, ccversion string) (*ChaincodeData, error) {     //./peer/node/start.go: ccprovider.EnableCCInfoCache()     //如果启用ccInfoCache,优先从缓存中读取ChaincodeData     if ccInfoCacheEnabled {         return ccInfoCache.GetChaincodeData(ccname, ccversion)     }     ccpack, err := ccInfoFSProvider.GetChaincode(ccname, ccversion)     return ccpack.GetChaincodeData(), nil } //代码在core/common/ccprovider/ccprovider.go

3.2、ccInfoCacheImpl结构体

type ccInfoCacheImpl struct {     sync.RWMutex     cache map[string]*ChaincodeData //ChaincodeData     cacheSupport CCCacheSupport } //构造ccInfoCacheImpl func NewCCInfoCache(cs CCCacheSupport) *ccInfoCacheImpl //获取ChaincodeData,优先从c.cache中获取,如果c.cache中没有,则从c.cacheSupport(即CCInfoFSImpl)中获取并写入c.cache func (c *ccInfoCacheImpl) GetChaincodeData(ccname string, ccversion string) (*ChaincodeData, error) //代码在core/common/ccprovider/ccinfocache.go

func (c ccInfoCacheImpl) GetChaincodeData(ccname string, ccversion string) (ChaincodeData, error) 代码如下:

func (c *ccInfoCacheImpl) GetChaincodeData(ccname string, ccversion string) (*ChaincodeData, error) {     key := ccname + "/" + ccversion     c.RLock()     ccdata, in := c.cache[key] //优先从c.cache中获取     c.RUnlock()     if !in { //如果c.cache中没有         var err error         //从c.cacheSupport中获取         ccpack, err := c.cacheSupport.GetChaincode(ccname, ccversion)         c.Lock()         //并写入c.cache         ccdata = ccpack.GetChaincodeData()         c.cache[key] = ccdata         c.Unlock()     }     return ccdata, nil } //代码在core/common/ccprovider/ccinfocache.go

3.3、CCCacheSupport接口定义及实现

3.3.1、CCCacheSupport接口定义

type CCCacheSupport interface {     //获取Chaincode包     GetChaincode(ccname string, ccversion string) (CCPackage, error) } //代码在core/common/ccprovider/ccprovider.go

3.3.2、CCCacheSupport接口实现(即CCInfoFSImpl结构体)

type CCInfoFSImpl struct{} //从文件系统中读取并构造CDSPackage或SignedCDSPackage func (*CCInfoFSImpl) GetChaincode(ccname string, ccversion string) (CCPackage, error) {     cccdspack := &CDSPackage{}     _, _, err := cccdspack.InitFromFS(ccname, ccversion)     if err != nil {         //try signed CDS         ccscdspack := &SignedCDSPackage{}         _, _, err = ccscdspack.InitFromFS(ccname, ccversion)         if err != nil {             return nil, err         }         return ccscdspack, nil     }     return cccdspack, nil } //将ChaincodeDeploymentSpec序列化后写入文件系统 func (*CCInfoFSImpl) PutChaincode(depSpec *pb.ChaincodeDeploymentSpec) (CCPackage, error) {     buf, err := proto.Marshal(depSpec)     cccdspack := &CDSPackage{}     _, err := cccdspack.InitFromBuffer(buf)     err = cccdspack.PutChaincodeToFS() } //代码在core/common/ccprovider/ccprovider.go

3.4、CCPackage接口定义及实现

3.4.1、CCPackage接口定义

type CCPackage interface {     //从字节初始化包     InitFromBuffer(buf []byte) (*ChaincodeData, error)     //从文件系统初始化包     InitFromFS(ccname string, ccversion string) ([]byte, *pb.ChaincodeDeploymentSpec, error)     //将chaincode包写入文件系统     PutChaincodeToFS() error     //从包中获取ChaincodeDeploymentSpec     GetDepSpec() *pb.ChaincodeDeploymentSpec     //从包中获取序列化的ChaincodeDeploymentSpec     GetDepSpecBytes() []byte     //校验ChaincodeData     ValidateCC(ccdata *ChaincodeData) error     //包转换为proto.Message     GetPackageObject() proto.Message     //获取ChaincodeData     GetChaincodeData() *ChaincodeData     //基于包计算获取chaincode Id     GetId() []byte } //代码在core/common/ccprovider/ccprovider.go

3.4.2、CCPackage接口实现(CDSPackage)

type CDSData struct {     CodeHash []byte //ChaincodeDeploymentSpec.CodePackage哈希     MetaDataHash []byte //ChaincodeSpec.ChaincodeId.Name和ChaincodeSpec.ChaincodeId.Version哈希 } type CDSPackage struct {     buf []byte //ChaincodeDeploymentSpec哈希     depSpec *pb.ChaincodeDeploymentSpec //ChaincodeDeploymentSpec     data *CDSData     datab []byte     id []byte //id为CDSData.CodeHash和CDSData.MetaDataHash求哈希 } //获取ccpack.id func (ccpack *CDSPackage) GetId() []byte //获取ccpack.depSpec func (ccpack *CDSPackage) GetDepSpec() *pb.ChaincodeDeploymentSpec //获取ccpack.buf,即ChaincodeDeploymentSpec哈希 func (ccpack *CDSPackage) GetDepSpecBytes() []byte //获取ccpack.depSpec func (ccpack *CDSPackage) GetPackageObject() proto.Message //构造ChaincodeData func (ccpack *CDSPackage) GetChaincodeData() *ChaincodeData //获取ChaincodeDeploymentSpec哈希、CDSData、id func (ccpack *CDSPackage) getCDSData(cds *pb.ChaincodeDeploymentSpec) ([]byte, []byte, *CDSData, error) //校验CDSPackage和ChaincodeData func (ccpack *CDSPackage) ValidateCC(ccdata *ChaincodeData) error //[]byte反序列化为ChaincodeDeploymentSpec,构造CDSPackage,进而构造ChaincodeData func (ccpack *CDSPackage) InitFromBuffer(buf []byte) (*ChaincodeData, error) //从文件系统中获取ChaincodeData,即buf, err := GetChaincodePackage(ccname, ccversion)和_, err = ccpack.InitFromBuffer(buf) func (ccpack *CDSPackage) InitFromFS(ccname string, ccversion string) ([]byte, *pb.ChaincodeDeploymentSpec, error) //ccpack.buf写入文件,文件名为/var/hyperledger/production/chaincodes/Name.Version func (ccpack *CDSPackage) PutChaincodeToFS() error //代码在core/common/ccprovider/cdspackage.go

3.5、CCContext结构体

type CCContext struct { //ChaincodeD上下文     ChainID string     Name string     Version string     TxID string     Syscc bool     SignedProposal *pb.SignedProposal     Proposal *pb.Proposal     canonicalName string } //构造CCContext func NewCCContext(cid, name, version, txid string, syscc bool, signedProp *pb.SignedProposal, prop *pb.Proposal) *CCContext //name + ":" + version func (cccid *CCContext) GetCanonicalName() string //代码在core/common/ccprovider/ccprovider.go

4、chaincode目录相关实现

4.1、ChaincodeProviderFactory接口定义及实现

4.1.1、ChaincodeProviderFactory接口定义

type ChaincodeProviderFactory interface {     //构造ChaincodeProvider实例     NewChaincodeProvider() ChaincodeProvider } func RegisterChaincodeProviderFactory(ccfact ChaincodeProviderFactory) {     ccFactory = ccfact } func GetChaincodeProvider() ChaincodeProvider {     return ccFactory.NewChaincodeProvider() } //代码在core/common/ccprovider/ccprovider.go

4.1.2、ChaincodeProviderFactory接口实现

type ccProviderFactory struct { } func (c *ccProviderFactory) NewChaincodeProvider() ccprovider.ChaincodeProvider {     return &ccProviderImpl{} } func init() {     ccprovider.RegisterChaincodeProviderFactory(&ccProviderFactory{}) } //代码在core/chaincode/ccproviderimpl.go

4.2、ChaincodeProvider接口定义及实现

4.2.1、ChaincodeProvider接口定义

type ChaincodeProvider interface {     GetContext(ledger ledger.PeerLedger) (context.Context, error)     GetCCContext(cid, name, version, txid string, syscc bool, signedProp *pb.SignedProposal, prop *pb.Proposal) interface{}     GetCCValidationInfoFromLSCC(ctxt context.Context, txid string, signedProp *pb.SignedProposal, prop *pb.Proposal, chainID string, chaincodeID string) (string, []byte, error)     ExecuteChaincode(ctxt context.Context, cccid interface{}, args [][]byte) (*pb.Response, *pb.ChaincodeEvent, error)     Execute(ctxt context.Context, cccid interface{}, spec interface{}) (*pb.Response, *pb.ChaincodeEvent, error)     ExecuteWithErrorFilter(ctxt context.Context, cccid interface{}, spec interface{}) ([]byte, *pb.ChaincodeEvent, error)     Stop(ctxt context.Context, cccid interface{}, spec *pb.ChaincodeDeploymentSpec) error     ReleaseContext() } //代码在core/common/ccprovider/ccprovider.go

4.2.2、ChaincodeProvider接口实现

type ccProviderImpl struct {     txsim ledger.TxSimulator //交易模拟器 } type ccProviderContextImpl struct {     ctx *ccprovider.CCContext } //获取context.Context,添加TXSimulatorKey绑定c.txsim func (c *ccProviderImpl) GetContext(ledger ledger.PeerLedger) (context.Context, error) //构造CCContext,并构造ccProviderContextImpl func (c *ccProviderImpl) GetCCContext(cid, name, version, txid string, syscc bool, signedProp *pb.SignedProposal, prop *pb.Proposal) interface{} //调用GetChaincodeDataFromLSCC(ctxt, txid, signedProp, prop, chainID, chaincodeID)获取ChaincodeData中Vscc和Policy func (c *ccProviderImpl) GetCCValidationInfoFromLSCC(ctxt context.Context, txid string, signedProp *pb.SignedProposal, prop *pb.Proposal, chainID string, chaincodeID string) (string, []byte, error) //调用ExecuteChaincode(ctxt, cccid.(*ccProviderContextImpl).ctx, args)执行上下文中指定的链码 func (c *ccProviderImpl) ExecuteChaincode(ctxt context.Context, cccid interface{}, args [][]byte) (*pb.Response, *pb.ChaincodeEvent, error) //调用Execute(ctxt, cccid.(*ccProviderContextImpl).ctx, spec) func (c *ccProviderImpl) Execute(ctxt context.Context, cccid interface{}, spec interface{}) (*pb.Response, *pb.ChaincodeEvent, error) //调用ExecuteWithErrorFilter(ctxt, cccid.(*ccProviderContextImpl).ctx, spec) func (c *ccProviderImpl) ExecuteWithErrorFilter(ctxt context.Context, cccid interface{}, spec interface{}) ([]byte, *pb.ChaincodeEvent, error) //调用theChaincodeSupport.Stop(ctxt, cccid.(*ccProviderContextImpl).ctx, spec) func (c *ccProviderImpl) Stop(ctxt context.Context, cccid interface{}, spec *pb.ChaincodeDeploymentSpec) error //调用c.txsim.Done() func (c *ccProviderImpl) ReleaseContext() { //代码在core/chaincode/ccproviderimpl.go

4.3、ChaincodeSupport结构体

ChaincodeSupport更详细内容,参考:Fabric 1.0源代码笔记 之 Chaincode(链码) #ChaincodeSupport(链码支持服务端)

4.4、ExecuteChaincode函数(执行链码)

执行链码上下文中指定的链码。

func ExecuteChaincode(ctxt context.Context, cccid *ccprovider.CCContext, args [][]byte) (*pb.Response, *pb.ChaincodeEvent, error) {     var spec *pb.ChaincodeInvocationSpec     var err error     var res *pb.Response     var ccevent *pb.ChaincodeEvent     spec, err = createCIS(cccid.Name, args) //构造ChaincodeInvocationSpec     res, ccevent, err = Execute(ctxt, cccid, spec)     return res, ccevent, err } //代码在core/chaincode/chaincodeexec.go

res, ccevent, err = Execute(ctxt, cccid, spec)代码如下:

func Execute(ctxt context.Context, cccid *ccprovider.CCContext, spec interface{}) (*pb.Response, *pb.ChaincodeEvent, error) {     var err error     var cds *pb.ChaincodeDeploymentSpec     var ci *pb.ChaincodeInvocationSpec     cctyp := pb.ChaincodeMessage_INIT //初始化     if cds, _ = spec.(*pb.ChaincodeDeploymentSpec); cds == nil { //优先判断ChaincodeDeploymentSpec         if ci, _ = spec.(*pb.ChaincodeInvocationSpec); ci == nil { //其次判断ChaincodeInvocationSpec             panic("Execute should be called with deployment or invocation spec")         }         cctyp = pb.ChaincodeMessage_TRANSACTION //交易     }     _, cMsg, err := theChaincodeSupport.Launch(ctxt, cccid, spec)     var ccMsg *pb.ChaincodeMessage     ccMsg, err = createCCMessage(cctyp, cccid.TxID, cMsg)     resp, err := theChaincodeSupport.Execute(ctxt, cccid, ccMsg, theChaincodeSupport.executetimeout)     if resp.ChaincodeEvent != nil {         resp.ChaincodeEvent.ChaincodeId = cccid.Name         resp.ChaincodeEvent.TxId = cccid.TxID     }     if resp.Type == pb.ChaincodeMessage_COMPLETED {         res := &pb.Response{}         unmarshalErr := proto.Unmarshal(resp.Payload, res)         return res, resp.ChaincodeEvent, nil     } } //代码在core/chaincode

5、platforms(链码的编写语言平台)

参考上一篇文章

原文链接:https://yq.aliyun.com/articles/658790
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章