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.TimestampCodePackage   []byte //链码文件打包ExecEnv       ChaincodeDeploymentSpec_ExecutionEnvironment //链码执行环境,DOCKER或SYSTEM
}type ChaincodeDeploymentSpec_ExecutionEnvironment int32const (ChaincodeDeploymentSpec_DOCKER ChaincodeDeploymentSpec_ExecutionEnvironment = 0ChaincodeDeploymentSpec_SYSTEM ChaincodeDeploymentSpec_ExecutionEnvironment = 1
)
//代码在protos/peer/chaincode.pb.go

2.1.2、ChaincodeSpec结构体定义

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

2.2、ChaincodeInvocationSpec结构体定义

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

3、ccprovider目录相关实现

3.1、ChaincodeData结构体

type ChaincodeData struct {Name stringVersion stringEscc stringVscc stringPolicy []byte //chaincode 实例的背书策略Data []byteId []byteInstantiationPolicy []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,优先从缓存中读取ChaincodeDataif 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.RWMutexcache        map[string]*ChaincodeData //ChaincodeDatacacheSupport 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 + "/" + ccversionc.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.cacheccdata = ccpack.GetChaincodeData()c.cache[key] = ccdatac.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 CDSccscdspack := &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//从包中获取ChaincodeDeploymentSpecGetDepSpec() *pb.ChaincodeDeploymentSpec//从包中获取序列化的ChaincodeDeploymentSpecGetDepSpecBytes() []byte//校验ChaincodeDataValidateCC(ccdata *ChaincodeData) error//包转换为proto.MessageGetPackageObject() proto.Message//获取ChaincodeDataGetChaincodeData() *ChaincodeData//基于包计算获取chaincode IdGetId() []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 //ChaincodeDeploymentSpecdata    *CDSDatadatab   []byteid      []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 stringName stringVersion stringTxID stringSyscc boolSignedProposal *pb.SignedProposalProposal *pb.ProposalcanonicalName 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) errorReleaseContext()
}
//代码在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.ChaincodeInvocationSpecvar err errorvar res *pb.Responsevar ccevent *pb.ChaincodeEventspec, err = createCIS(cccid.Name, args) //构造ChaincodeInvocationSpecres, 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 errorvar cds *pb.ChaincodeDeploymentSpecvar ci *pb.ChaincodeInvocationSpeccctyp := pb.ChaincodeMessage_INIT //初始化if cds, _ = spec.(*pb.ChaincodeDeploymentSpec); cds == nil { //优先判断ChaincodeDeploymentSpecif ci, _ = spec.(*pb.ChaincodeInvocationSpec); ci == nil { //其次判断ChaincodeInvocationSpecpanic("Execute should be called with deployment or invocation spec")}cctyp = pb.ChaincodeMessage_TRANSACTION //交易}_, cMsg, err := theChaincodeSupport.Launch(ctxt, cccid, spec)var ccMsg *pb.ChaincodeMessageccMsg, err = createCCMessage(cctyp, cccid.TxID, cMsg)resp, err := theChaincodeSupport.Execute(ctxt, cccid, ccMsg, theChaincodeSupport.executetimeout)if resp.ChaincodeEvent != nil {resp.ChaincodeEvent.ChaincodeId = cccid.Nameresp.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(链码的编写语言平台)

platforms更详细内容,参考:Fabric 1.0源代码笔记 之 Chaincode(链码) #platforms(链码语言平台)欢迎继续关注兄弟连区块链教程分享!

转载于:https://blog.51cto.com/14041296/2310244

区块链教程Fabric1.0源代码分析Chaincode(链码)体系总结相关推荐

  1. 区块链教程Fabric1.0源代码分析scc(系统链码)

    区块链教程Fabric1.0源代码分析scc(系统链码),2018年下半年,区块链行业正逐渐褪去发展之初的浮躁.回归理性,表面上看相关人才需求与身价似乎正在回落.但事实上,正是初期泡沫的渐退,让人们更 ...

  2. 兄弟连区块链教程Fabric1.0源代码分析Peer peer根命令入口及加载子命令一

    区块链教程Fabric1.0源代码分析Peer peer根命令入口及加载子命令,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁.回归理性,表面上看相关人才需求与身价似乎正在回落.但事实上,正是初 ...

  3. 区块链教程Fabric1.0源代码分析Peer peer channel命令及子命令实现

    区块链教程Fabric1.0源代码分析Peer peer channel命令及子命令实现,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁.回归理性,表面上看相关人才需求与身价似乎正在回落.但事实 ...

  4. 区块链教程Fabric1.0源代码分析Tx(Transaction 交易)一

    区块链教程Fabric1.0源代码分析Tx(Transaction 交易)一,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁.回归理性,表面上看相关人才需求与身价似乎正在回落.但事实上,正是初期 ...

  5. 兄弟连区块链教程Fabric1.0源代码分析configupdate处理通道配置更新

    区块链教程Fabric1.0源代码分析configupdate处理通道配置更新,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁.回归理性,表面上看相关人才需求与身价似乎正在回落.但事实上,正是初 ...

  6. 区块链教程Fabric1.0源代码分析流言算法Gossip服务端二

    区块链教程Fabric1.0源代码分析流言算法Gossip服务端二 Fabric 1.0源代码笔记 之 gossip(流言算法) #GossipServer(Gossip服务端) 5.2.commIm ...

  7. 区块链教程Fabric1.0源代码分析configtx#genesis-兄弟连

    区块链教程Fabric1.0源代码分析configtx#genesis,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁.回归理性,表面上看相关人才需求与身价似乎正在回落.但事实上,正是初期泡沫的 ...

  8. 区块链教程Fabric1.0源代码分析配置交易-生成通道配置二

    兄弟连区块链教程Fabric1.0源代码分析配置交易-生成通道配置二.Generator接口实现,即bootstrapper. type bootstrapper struct {channelGro ...

  9. gossip 区块链_区块链教程Fabric1.0源代码分析流言算法Gossip服务端一兄弟连区块链教程-阿里云开发者社区...

    区块链教程Fabric1.0源代码分析流言算法Gossip服务端一,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁.回归理性,表面上看相关人才需求与身价似乎正在回落.但事实上,正是初期泡沫的渐退 ...

最新文章

  1. python3 time模块与datetime模块
  2. 达摩java_JAVA面向对象
  3. 阿里云边缘云荣获“分布式云创新奖”与“先进边缘云架构奖”
  4. Mike and distribution(思维)
  5. Java压缩技术(七) TAR——Commons实现
  6. 朝花夕拾——finally/final/finalize拨云雾见青天
  7. android 支付模块封装,Android集成支付----支付宝支付总结与封装
  8. Hadoop 之 MapReduce 的工作原理及其倒排索引的建立
  9. NHL明星与美国冰球协会联手发起NFT拍卖
  10. linux中的lock文件,linux – 为什么即使文件被锁定,File :: FcntlLock的l_type总是“F_UNLCK”?...
  11. 大米产品体验师活动火热进行!感谢客户最真实的心声
  12. excel宏选中单元格_从单元格引用运行Excel宏
  13. 第九周博客作业西北师范大学|李晓婷
  14. WdatePicker 诱发 “无法打开站点,已终止操作”错误
  15. 1. C语言的第一个程序
  16. TCP滑动窗口原理终于清楚了!
  17. 2008-09赛季NBA直播表(cctv5 广东体育)
  18. 三分钟教你学会如何将密文解码成明文
  19. Non-local的一些理解
  20. 继sina想在csdc开博

热门文章

  1. 关于transform的3D变形函数
  2. UITableView刷新单个cell或者单个Section
  3. Sa身份登陆SQL SERVER失败的解决方案
  4. 写代码如坐禅:你是哪一类程序员?
  5. 文字图片垂直居中对齐
  6. Struts2的properties配置文件详解
  7. 在python中查看关键字需要在python解释器中执行_现有代码 d={},在Python3解释器中执行 d[([1,2])] = 'b'得到的结果为( )。...
  8. Windows PE导出表编程3(暴力覆盖导出函数)
  9. C语言经典例30-判断回文数
  10. 【数字信号处理】基本序列 ( 单位阶跃序列 | 单位阶跃序列与单位脉冲序列关系 | 矩形序列 | 矩形序列与单位阶跃序列关系 | 矩形序列作用 )