hyperledger fabric0.6 结构分析(二)


 
   
 
   
 
   
接着上图分析,经过Consensus Commit流程生成批数据后,是如何送入到ChainCode呢?我们还是以Invoke命令分析。
1)在consensus的helper中调用chaincode的ExecuteTransactions 进入transaction处理流程
 
   
[cpp] view plain copy
  1. func (h *Helper) ExecTxs(id interface{}, txs []*pb.Transaction) ([]byte, error) {  
  2. succeededTxs, res, ccevents, txerrs, err := chaincode.ExecuteTransactions(context.Background(), chaincode.DefaultChain, txs)  
  3. }  

2)该函数在core/chaincode 中处理,将命令封装成ChainCode识别的格式。其中的chain对象则是访问ChainCode对应的ChainCodeSupport,这样就说明访问ChainCode的接口类是ChainCodeSupportServer

 
   
[cpp] view plain copy
  1. func Execute(ctxt context.Context, chain *ChaincodeSupport, t *pb.Transaction) ([]byte, *pb.ChaincodeEvent, error) {  
  2. ccMsg, err = createTransactionMessage(t.Txid, cMsg)  
  3. resp, err := chain.Execute(ctxt, chaincode, ccMsg, timeout, t)  
  4. }  

3)该函数在ChainCodeSupport文件中,首先检测ChainCode是否建立成功、能否正常运行。其中chrte.handler的得来是比较复杂的,见下描述

[cpp] view plain copy
  1. func (chaincodeSupport *ChaincodeSupport) Execute(ctxt context.Context, chaincode string, msg *pb.ChaincodeMessage, timeout time.Duration, tx *pb.Transaction) (*pb.ChaincodeMessage, error) {  
  2. chrte, ok := chaincodeSupport.chaincodeHasBeenLaunched(chaincode)  
  3. chrte.handler.sendExecuteMessage(msg, tx)  
  4. }  

3.1)在创建ChainCodeSupport的时候registerChaincodeSupport 调用 NewChaincodeSupport 实例化ChainCodeSupport(start.Go),服务器的Name:

[cpp] view plain copy
  1. protos.ChaincodeSupport  
[cpp] view plain copy
  1. ccStartupTimeout := time.Duration(tOut) * time.Millisecond  
  2.   
  3. ccSrv := chaincode.NewChaincodeSupport(chainname, peer.GetPeerEndpoint, userRunsCC,  
  4.     ccStartupTimeout, secHelper)  
  5.   
  6. //Now that chaincode is initialized, register all system chaincodes.  
  7. system_chaincode.RegisterSysCCs()  
  8.   
  9. pb.RegisterChaincodeSupportServer(grpcServer, ccSrv)  
 
   
[cpp] view plain copy
  1. var _ChaincodeSupport_serviceDesc = grpc.ServiceDesc{  
  2.        ServiceName: "protos.ChaincodeSupport",  
  3.        HandlerType: (*ChaincodeSupportServer)(nil),  
  4.        Methods:     []grpc.MethodDesc{},  
  5.        Streams: []grpc.StreamDesc{  
  6.               {  
  7.                      StreamName:    "Register",  
  8.                      Handler:       _ChaincodeSupport_Register_Handler,  
  9.                      ServerStreams: true,  
  10.                      ClientStreams: true,  
  11.               },  
  12.        },  
  13. }  

3.2)ChainCode 调用 err := shim.Start(new(SimpleChaincode)) 接入到ChainCodeSupportServer

 
   
[cpp] view plain copy
  1. err := shim.Start(new(SimpleChaincode))  

3.3)连接ChainCodeSupprotServer同时调用Register函数

 
   
[cpp] view plain copy
  1. func Start(cc Chaincode) error {  
  2. chaincodeSupportClient := pb.NewChaincodeSupportClient(clientConn)  
  3. stream, err := chaincodeSupportClient.Register(context.Background())  
  4. err = chatWithPeer(chaincodename, stream, cc)  
  5. }  

3.4)与此同时ChainCodeSupportServer会根据Client调用注册函数创建该Stream的Handler处理句柄,创建消息响应循环,等待Client发送命令.(注意该handler就是我们关心的

handler.sendExecuteMessage )
 
   
[cpp] view plain copy
  1. func HandleChaincodeStream(chaincodeSupport *ChaincodeSupport, ctxt context.Context, stream ccintf.ChaincodeStream) error {  
[cpp]  view plain  copy
  1.     deadline, ok := ctxt.Deadline()  
  2.     chaincodeLogger.Debugf("Current context deadline = %s, ok = %v", deadline, ok)  
  3.     handler := newChaincodeSupportHandler(chaincodeSupport, stream)  
  4.     return handler.processStream()  
  5. }  
 
   

3.5) 客户端shim/Chaincode发送RegisterMessage

 
   
[cpp] view plain copy
  1. handler.serialSend(&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_REGISTER, Payload: payload})  

3.6)对于Server而言,我们刚刚创建了handler又有ProcessStream消息响应循环,这样RegisterMessage就交到了ProcessStream手里,ProcessStream根据消息类型执行命令分发 调用beforeRegisterEvent函数。

[cpp] view plain copy
  1. func (handler *Handler) beforeRegisterEvent(e *fsm.Event, state string) {  
  2. err = handler.chaincodeSupport.registerHandler(handler)  
  3. }  

3.7)同理在client端(shim/chaincode)也建立响应的消息响应循环。


4)到目前为止还没有完,我们将invoke命令送给了Client的委托模块Shim进行处理。Shim模块根据来访事件类型送入指定处理函数
 
   
[cpp] view plain copy
  1. func (handler *Handler) enterTransactionState(e *fsm.Event) {  
  2.     msg, ok := e.Args[0].(*pb.ChaincodeMessage)  
  3.     if !ok {  
  4.         e.Cancel(fmt.Errorf("Received unexpected message type"))  
  5.         return  
  6.     }  
  7.     chaincodeLogger.Debugf("[%s]Received %s, invoking transaction on chaincode(Src:%s, Dst:%s)", shorttxid(msg.Txid), msg.Type.String(), e.Src, e.Dst)  
  8.     if msg.Type.String() == pb.ChaincodeMessage_TRANSACTION.String() {  
  9.         // Call the chaincode's Run function to invoke transaction  
  10.         handler.handleTransaction(msg)  
  11.     }  
  12. }  
5)调用ChainCode的invoke函数
[cpp] view plain copy
  1. func (handler *Handler) handleTransaction(msg *pb.ChaincodeMessage) {  
  2. res, err := handler.cc.Invoke(stub, function, params)  
  3. }  
以上分析涉及两个过程 1) consensus结束后如何将命令送入ChainCode 2)ChainCodeSupportServer与ChainCode如何建立通信关系。

画一个 ChainCodeSupportServer与ChainCode如何建立通信关系 图:
	
	

你可能感兴趣的:(blockchain)