12.5 用户链码

用户链码对应用开发者来说十分重要,它提供了基于区块链分布式账本的状态处理逻辑,基于它可以开发出多种复杂的应用。

在超级账本Fabric项目中,用户可以使用Go语言来开发链码,未来还将支持包括Java、JavaScript在内的多种高级语言。

用户链码相关的代码都在core/chaincode路径下。其中core/chaincode/shim包中的代码主要是供链码容器侧调用使用,其他代码主要是Peer侧使用。

12.5.1 基本结构

Fabric中为链码提供了很好的封装支持,用户编写链码十分简单。

下面给出了链码的典型结构,用户只需要关注到Init()和Invoke()函数的实现上,在其中利用shim.ChaincodeStubInterface结构,实现跟账本的交互逻辑:


 

package main

import (
   "errors"
   "fmt"
   "github.com/hyperledger/fabric/core/chaincode/shim"
)

type DemoChaincode struct { }

func (t *DemoChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
   // more logics using stub here
   return stub.Success(nil)
}

func (t *DemoChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response
   // more logics using stub here
   return stub.Success(nil)
}

func main() {
   err := shim.Start(new(DemoChaincode))
   if err != nil {
       fmt.Printf("Error starting DemoChaincode: %s", err)
   }
}


用户链码支持install、instantiate、invoke、query、upgrade、package、signpackage等操作,其生命周期被生命周期管理系统链码(Lifecycle System Chaincode,LSCC)进行管理。

12.5.2 链码与Peer的交互过程

用户链码目前运行在Docker容器中,跟Peer节点之间通过gRPC通道进行通信,双方通过ChaincodeMessage消息进行交互。

ChaincodeMessage消息结构如图12-22所示,其中,Type为消息的类型,TxId为关联的交易的ID,Payload中则存储消息内容。

image.png

图12-22 ChaincodeMessage消息结构

消息类型包括REGISTER、REGISTERED、INIT、READY、TRANSACTION、 COMPLETED、ERROR、GET_STATE、PUT_STATE、DEL_STATE、INVOKE_CHAINCODE、RESPONSE、 GET_STATE_BY_RANGE、GET_QUERY_RESULT、QUERY_STATE_NEXT、QUERY_STATE_CLOSE、 KEEPALIVE、GET_HISTORY_FOR_KEY等19种消息,这些消息负责整个用户链码的完整生命周期。

用户链码容器和所属Peer节点之间的主要交互过程如图12-23所示。

典型情况下,链码自注册到Peer开始,一直到被调用过程,主要步骤大致如下:

1)用户链码调用shim.Start()方法后,首先会向Peer发送ChaincodeMessage_REGISTER消息尝试进行注册。之后开始等待接收来自Peer的消息。此时状态为初始的created。

2)Peer收到来自链码容器的ChaincodeMessage_REGISTER消息,注册到本地的一个 handler结构,返回ChaincodeMessage_REGISTERED消息给链码容器。更新状态为established,之后自动发出 ChaincodeMessage_READY消息给链码侧,更新状态为ready。

3)链码侧收到ChaincodeMessage_REGISTERED消息后,不进行任何操作,注册成功。更新状态为established。收到ChaincodeMessage_READY消息后更新状态为ready。

4)Peer侧发出ChaincodeMessage_INIT消息给链码容器,对链码进行进行初始化。

5)链码容器收到ChaincodeMessage_INIT消息,调用用户链码代码Init()方法进行初始化,成功后,返回ChaincodeMessage_COMPLETED消息。此时,链码容器可以被调用了。

6)链码被调用时,Peer发出ChaincodeMessage_TRANSACTION消息给链码。

image.png

图12-23 链码消息交互

7)链码收到ChaincodeMessage_TRANSACTION消息,会调用Invoke()方法,根据Invoke方法中用户实现的逻辑,可以发出以下消息给Peer侧:

·ChaincodeMessage_GET_HISTORY_FOR_KEY

·ChaincodeMessage_GET_QUERY_RESULT

·ChaincodeMessage_GET_STATE

·ChaincodeMessage_GET_STATE_BY_RANGE

·ChaincodeMessage_QUERY_STATE_CLOSE

·ChaincodeMessage_QUERY_STATE_NEXT

·ChaincodeMessage_INVOKE_CHAINCODE

Peer侧收到这些消息,进行相应的处理,并回复ChaincodeMessage_RESPONSE消息。最后,链码侧会回复调用完成的消息ChaincodeMessage_COMPLETE给Peer侧。

8)在上述过程中,Peer和链码侧还会定期的发送haincodeMessage_KEEPALIVE消息给对方,以确保彼此在线。

12.5.3 链码处理状态机

无论是链码容器侧还是Peer侧,都是根据收到的消息触发处理逻辑,然后进入下一个状态,十分适合采用有限状态机 (Finite State Machine,FSM)结构进行描述。Fabric项目采用了github.com/looplab/fsm包实现了基于状态机的链码逻辑处理。

1.链码容器侧处理

链码侧主要实现了Handler结构体来处理消息,并通过各种handleXXX方法具体实现来自Chaincode接口中定义的各种对账本的操作:

Handler结构体实现代码在core/chaincode/shim/handler.go文件,主要定义如下:


 

type Handler struct {
   sync.RWMutex
   // shim to peer grpc serializer. User only in serialSend
   serialLock sync.Mutex
   To         string
   ChatStream PeerChaincodeStream
   FSM        *fsm.FSM
   cc         Chaincode
   // Multiple queries (and one transaction) with different txids can be executing
       in parallel for this chaincode
   // responseChannel is the channel on which responses are communicated by the
       shim to the chaincodeStub.
   responseChannel map[string]chan pb.ChaincodeMessage
   nextState       chan *nextStateInfo
}


Handler结构体的主要成员包括:

·ChatStream:跟Peer进行通信的gRPC流;

·FSM:最重要的事件处理状态机,根据收到不同事件调用不同方法;

·cc:所面向的链码;

·responseChannel:本地chan,字典结构,key是TxID,value里面可以放上一些消息,供调用者后面使用;

·nextState:本地chan,可以存放下一步要进行的操作和数据。

链码侧对链码消息处理的状态机如图12-24所示,最关键的是在ready状态下处理来自Peer的各种消息。

2.Peer侧状态机

Peer侧也通过了一个Handler结构体来处理链码容器侧过来的各种消息。该结构体的定义在core/chaincode/handler.go文件中,定义代码如下所示:


 

type Handler struct {
   sync.RWMutex
   // peer to shim grpc serializer. User only in serialSend
   serialLock  sync.Mutex
   ChatStream  ccintf.ChaincodeStream
   FSM         *fsm.FSM
   ChaincodeID *pb.ChaincodeID
   ccInstance  *sysccprovider.ChaincodeInstance

   chaincodeSupport *ChaincodeSupport
   registered       bool
   readyNotify      chan bool
   // Map of tx txid to either invoke tx. Each tx will be
   // added prior to execute and remove when done execute
   txCtxs map[string]*transactionContext

   txidMap map[string]bool

   // used to do Send after making sure the state transition is complete
   nextState chan *nextStateInfo

   policyChecker policy.PolicyChecker
}

image.png

图12-24 链码侧状态机

Handler结构体的主要成员包括:

·ChatStream:跟链码侧进行通信的gRPC通道;

·FSM:核心的事件处理状态机,根据收到不同事件调用不同方法;

·ChaincodeID:所关联的链码ID;

·ccInstance:代表链码实例;

·chaincodeSupport:提供对链码的执行、注册、启动、停止等操作;

·registered:是否已注册;

·readyNotify:本地chan,通知就绪状态;

·txCtxs:字典结构,存储交易ID到交易的映射;

·nextState:本地chan,存储状态切换的相关数据;

·policyChecker:根据通道策略,对签名进行检查等。

Peer侧对链码消息处理的状态机如图12-25所示,最主要的是在ready状态下处理来自链码侧的各种消息。

image.png

图12-25 Peer侧状态机

来源:我是码农,转载请保留出处和链接!

本文链接:http://www.54manong.com/?id=901

'); (window.slotbydup = window.slotbydup || []).push({ id: "u3646208", container: s }); })();
'); (window.slotbydup = window.slotbydup || []).push({ id: "u3646147", container: s }); })();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值