hyperledger fabric 結構分析(二)

買賣虛擬貨幣

接著上圖分析,經過consensus commit流程生成批資料後,是如何送入到chaincode呢?我們還是以invoke命令分析。

1)在consensus的helper中呼叫chaincode的executetransactions 進入transaction處理流程

[cpp] 程式碼
func (h *helper) exectxs(id interface{}, txs []*pb.transaction) ([]byte, error) {  
succeededtxs, res, ccevents, txerrs, err := chaincode.executetransactions(context.background(), chaincode.defaultchain, txs)  
}  

2)該函式在core/chaincode 中處理,將命令封裝成chaincode識別的格式。其中的chain物件則是訪問chaincode對應的chaincodesupport,這樣就說明訪問chaincode的介面類是chaincodesupportserver。

[cpp] 程式碼
func execute(ctxt context.context, chain *chaincodesupport, t *pb.transaction) ([]byte, *pb.chaincodeevent, error) {  
ccmsg, err = createtransactionmessage(t.txid, cmsg)  
resp, err := chain.execute(ctxt, chaincode, ccmsg, timeout, t)  
}  

3)該函式在chaincodesupport檔案中,首先檢測chaincode是否建立成功、能否正常執行。其中chrte.handler的得來是比較複雜的,見下描述

[cpp] 程式碼
func (chaincodesupport *chaincodesupport) execute(ctxt context.context, chaincode string, msg *pb.chaincodemessage, timeout time.duration, tx *pb.transaction) (*pb.chaincodemessage, error) {  
chrte, ok := chaincodesupport.chaincodehasbeenlaunched(chaincode)  
chrte.handler.sendexecutemessage(msg, tx)  
}  

3.1)在建立chaincodesupport的時候registerchaincodesupport 呼叫 newchaincodesupport 例項化chaincodesupport(start.go),伺服器的name:

[cpp] 程式碼
protos.chaincodesupport

[cpp] 程式碼
ccstartuptimeout := time.duration(tout) * time.millisecond  
ccsrv := chaincode.newchaincodesupport(chainname, peer.getpeerendpoint, userrunscc,  
    ccstartuptimeout, sechelper)  
//now that chaincode is initialized, register all system chaincodes.  
system_chaincode.registersysccs()  
pb.registerchaincodesupportserver(grpcserver, ccsrv)  

[cpp] 程式碼
var _chaincodesupport_servicedesc = grpc.servicedesc{  
       servicename: "protos.chaincodesupport",  
       handlertype: (*chaincodesupportserver)(nil),  
       methods:     []grpc.methoddesc{},  
       streams: []grpc.streamdesc{  
              {  
                     streamname:    "register",  
                     handler:       _chaincodesupport_register_handler,  
                     serverstreams: true,  
                     clientstreams: true,  
              },  
       },  
}  

3.2)chaincode 呼叫 err := shim.start(new(simplechaincode)) 接入到chaincodesupportserver

[cpp] 程式碼
err := shim.start(new(simplechaincode))  

3.3)連線chaincodesupprotserver同時呼叫register函式

[cpp] 程式碼
func start(cc chaincode) error {  
chaincodesupportclient := pb.newchaincodesupportclient(clientconn)  
stream, err := chaincodesupportclient.register(context.background())  
err = chatwithpeer(chaincodename, stream, cc)  
}  

3.4)與此同時chaincodesupportserver會根據client呼叫註冊函式建立該stream的handler處理控制代碼,建立訊息響應迴圈,等待client傳送命令.(注意該handler就是我們關心的
handler.sendexecutemessage)

[cpp] 程式碼
func handlechaincodestream(chaincodesupport *chaincodesupport, ctxt context.context, stream ccintf.chaincodestream) error {</span>  

[cpp] 程式碼
    deadline, ok := ctxt.deadline()  
    chaincodelogger.debugf("current context deadline = %s, ok = %v", deadline, ok)  
    handler := newchaincodesupporthandler(chaincodesupport, stream)  
    return handler.processstream()  
}  

3.5) 客戶端shim/chaincode傳送registermessage

[cpp] 程式碼
handler.serialsend(&pb.chaincodemessage{type: pb.chaincodemessage_register, payload: payload})  

3.6)對於server而言,我們剛剛建立了handler又有processstream訊息響應迴圈,這樣registermessage就交到了processstream手裡,processstream根據訊息型別執行命令分發
呼叫beforeregisterevent函式。

[cpp] 程式碼
func (handler *handler) beforeregisterevent(e *fsm.event, state string) {  
err = handler.chaincodesupport.registerhandler(handler)  
}  

3.7)同理在client端(shim/chaincode)也建立響應的訊息響應迴圈。

4)到目前為止還沒有完,我們將invoke命令送給了client的委託模組shim進行處理。shim模組根據來訪事件型別送入指定處理函式
[cpp] 程式碼
func (handler *handler) entertransactionstate(e *fsm.event) {  
    msg, ok := e.args[0].(*pb.chaincodemessage)  
    if !ok {  
        e.cancel(fmt.errorf("received unexpected message type"))  
        return  
    }  
    chaincodelogger.debugf("[%s]received %s, invoking transaction on chaincode(src:%s, dst:%s)", shorttxid(msg.txid), msg.type.string(), e.src, e.dst)  
    if msg.type.string() == pb.chaincodemessage_transaction.string() {  
        // call the chaincode's run function to invoke transaction  
        handler.handletransaction(msg)  
    }  
}  

5)呼叫chaincode的invoke函式
[cpp] 程式碼
func (handler *handler) handletransaction(msg *pb.chaincodemessage) {  
res, err := handler.cc.invoke(stub, function, params)  
}  

以上分析涉及兩個過程 1) consensus結束後如何將命令送入chaincode 2)chaincodesupportserver與chaincode如何建立通訊關係。

畫一個 chaincodesupportserver與chaincode如何建立通訊關係 圖:

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;