兄弟连 区块链教程 Fabric1.0源代码分析Chaincode(链码)体系总结,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。
# 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结构体定义
```go
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结构体定义
```go
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结构体定义
```go
type ChaincodeInvocationSpec struct {
ChaincodeSpec *ChaincodeSpec //参考本文2.2
IdGenerationAlg string
}
//代码在protos/peer/chaincode.pb.go
```
## 3、ccprovider目录相关实现
### 3.1、ChaincodeData结构体
```go
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)代码如下:
```go
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结构体
```go
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) 代码如下:
```go
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接口定义
```go
type CCCacheSupport interface {
//获取Chaincode包
GetChaincode(ccname string, ccversion string) (CCPackage, error)
}
//代码在core/common/ccprovider/ccprovider.go
```
#### 3.3.2、CCCacheSupport接口实现(即CCInfoFSImpl结构体)
```go
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接口定义
```go
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)
```go
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结构体
```go
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接口定义
```go
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接口实现
```go
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接口定义
```go
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接口实现
```go
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函数(执行链码)
执行链码上下文中指定的链码。
```go
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)代码如下:
```go
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源代码分析blockfile区块文件存储2
- 兄弟连区块链教程Fabric1.0源代码分析blockfile区块文件存储一
- Fabric 1.0源代码分析(2) blockfile(区块文件存储)
- 区块链教程Fabric1.0源代码分析configtx#genesis
- 区块链教程Fabric1.0源代码分析Ledger(账本)二
- 区块链教程Fabric1.0源代码分析Ledger(账本)一
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Nature of Code
Daniel Shiffman / The Nature of Code / 2012-12-13 / GBP 19.95
How can we capture the unpredictable evolutionary and emergent properties of nature in software? How can understanding the mathematical principles behind our physical world help us to create digital w......一起来看看 《The Nature of Code》 这本书的介绍吧!