1. 程式人生 > >區塊鏈教程Fabric1.0源代碼分析Chaincode(鏈碼)體系總結

區塊鏈教程Fabric1.0源代碼分析Chaincode(鏈碼)體系總結

oca 策略 執行環境 golang com hash 3.4 sda tco

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(鏈碼的編寫語言平臺)

platforms更詳細內容,參考:Fabric 1.0源代碼筆記 之 Chaincode(鏈碼) #platforms(鏈碼語言平臺)歡迎繼續關註兄弟連區塊鏈教程分享!

區塊鏈教程Fabric1.0源代碼分析Chaincode(鏈碼)體系總結