从前剖析程序着眼于细节剖析,这样没有框架的概念,花了两天时间剖析整理了一下hyperledger fabric的架构规划,剖析该程序没有参照任何资料,如有过错欢迎指正,共同进步。

笔者在详细剖析程序前有以下疑问:
1)CLI(指令行)客户端怎么发送指令给Peer节点
2)本Peer节点怎么接纳其他节点的数据,接纳到数据又怎么处理,处理的方式和1又有什么区别
3)数据是何时又是怎么被送入consensus模块
4)consensus模块内部又是怎么架构的 为什么看起来helper executor pbft controller文件夹交至在一起,保存各自句柄,相互调用
5)ChainCode(链码,简称CC)是怎么接纳到Peer对其的操作、访问的
6)ChainCode是怎么调用fabric API来查询写入数据的
7)在阅览源码初始化进程中,Peer节点会创立很多Server,这些Server后续进程我们是怎么运用的
注:本人关于数据库、Docker相关知识不是很了解,尽量防止关于这两个部分的介绍以免过错的引导读者。
下面会渐渐的浸透以上触及的问题。
Server :
每个Server作用:
AdminServer:操控该节点的命运,能够删除该节点所在的进程。(Start Stop GetStatus )
EventHubServer:Peer节点支撑客户端对指定事件进行监听,例如Rejection等。客户端需要先注册自己关怀的Events,当事件产生时trigger 监听者。
OpenChainServer:对外供给ledger的访问接口,触及GetBlockchainInfo GetBlockByNumber等。
DevopsServer:担任与CLI Client对接,外部进行CC操作的入口,Deploy invoke query。
ChaincodeSupportServer:担任与shim/Chaincode通信,ChainCode的一切调用接纳发送都要与该Server信息交互。
PeerServer:该Server是一个Engine,Engine相关了内部消息呼应完成,同时为周围Peer节点创立Client与之通信。
RESTServer:该Server没有进行剖析,应该是REST接口格局相关。
一级模块分类:
Client: 之前创立服务器与之对应的客户端,能够理解成其他节点或者CLI client等。
Protos: 中间层,Server与Client端 API接口界说
ServerProcess:服务呼应处理函数,包含各类型的HandleMessage。
Consensus: 一致模块,现在采用的是PBFT NOOPS
ChainCode Shim:代码中shim和我理解的不一致,将ChainCodeSupport也应该算到shim,该模块的作用是衔接Peer节点与ChainCode的媒介,用shim描述也可。
ChainCode: 链码,使用(例如智能合约)。
DB: 数据存储。
Library: 代码里有一个叫做Vendor的文件夹,该文件夹里触及的功能模块自成一体,例如grpcServer等
API: ChainCode里边会调用Peer节点信息。
Crypto: 伴随着数据加解密。
Ledger: 账本操作。
该代码运用Handler触发模式,在跟踪代码程序时要注意handler目标赋值位置,不然简单找错HandleMessage,这些Handler处理函数命名基本相同,简单操作紊乱。
下面剖析几个读者应该最关怀的流程:
1)Client经过CLI履行一条invoke指令
2)某节点发送给该节点ViewChange指令
3)ChainCode调用API putStatus
4)Consensus流程
一、 Client经过CLI履行一条invoke指令
1)在Peer节点初始化的时分 创立DevopsServer
serverDevops := core.NewDevopsServer(peerServer)
pb.RegisterDevopsServer(grpcServer, serverDevops)
2)DevopsServer设置Service规范,例如Invoke Message,调用_Devops_Invoke_Handler函数
var _Devops_serviceDesc = grpc.ServiceDeschttps://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
ServiceName: "protos.Devops",
HandlerType: (*DevopsServer)(nil),
Methods: []grpc.MethodDeschttps://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
MethodName: "Login",
Handler: _Devops_Login_Handler,
},
https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
MethodName: "Build",
Handler: _Devops_Build_Handler,
},
https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
MethodName: "Deploy",
Handler: _Devops_Deploy_Handler,
},
https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
MethodName: "Invoke",
Handler: _Devops_Invoke_Handler,
},
https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
MethodName: "Query",
Handler: _Devops_Query_Handler,
},
https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
MethodName: "EXP_GetApplicationTCert",
Handler: _Devops_EXP_GetApplicationTCert_Handler,
},
https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
MethodName: "EXP_PrepareForTx",
Handler: _Devops_EXP_PrepareForTx_Handler,
},
https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
MethodName: "EXP_ProduceSigma",
Handler: _Devops_EXP_ProduceSigma_Handler,
},
https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
MethodName: "EXP_ExecuteWithBinding",
Handler: _Devops_EXP_ExecuteWithBinding_Handler,
},
},
Streams: []grpc.StreamDeschttps://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg},
}
3)其间_Devops_Invoke_Handler函数在Protos模块,其担任将Client接入的信息传递到对应的Server模块
func _Devops_Invoke_Handler(srv interfacehttps://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg}, ctx context.Context, dec func(interfacehttps://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg}) error) (interfacehttps://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg}, error) https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
in := new(ChaincodeInvocationSpec)
if err := dec(in); err != nil https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
return nil, err
}
out, err := srv.(DevopsServer).Invoke(ctx, in)
if err != nil https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
return nil, err
}
return out, nil
}
4)在函数在devops服务端代码中处理
func (d *Devops) Invoke(ctx context.Context, chaincodeInvocationSpec *pb.ChaincodeInvocationSpec) (*pb.Response, error) https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
return d.invokeOrQuery(ctx, chaincodeInvocationSpec, chaincodeInvocationSpec.ChaincodeSpec.Attributes, true)
}
5)精简invokeOrQuery代码,d.coord 是PeerServer目标,ExecuteTransaction 是对应Engine的完成办法
func (d *Devops) invokeOrQuery(ctx context.Context, chaincodeInvocationSpec *pb.ChaincodeInvocationSpec, attributes []string, invoke bool) (*pb.Response, error) https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
resp := d.coord.ExecuteTransaction(transaction)
}
6)本次恳求被封装成买卖Struct,该处理是在PeerServer中。
func (p *Impl) ExecuteTransaction(transaction *pb.Transaction) (response *pb.Response) https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
if p.isValidator https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
response = p.sendTransactionsToLocalEngine(transaction)
} else https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
peerAddresses := p.discHelper.GetRandomNodes(1)
response = p.SendTransactionsToPeer(peerAddresses[0], transaction)
}
return response
}
7)考虑可知,最终这笔transaction是要交给到Consensus进行处理,那么怎么传递的呢?就在下面p.engine.ProcessTransactionMsg,其间"p"代指PeerServer,engine是在创立PeerServer的时分指定的Engine,而这个Engine的handler完成在Consensus里,在完成EngineHandler进程中加载了PBFT算法。所以ProcessTransactionMsg函数的完成在consensus模块engine代码里。这样解决了开端时提出的疑问3)。
func (p *Impl) sendTransactionsToLocalEngine(transaction *pb.Transaction) *pb.Response https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
peerLogger.Debugf("Marshalling transaction %s to send to local engine", transaction.Type)
data, err := proto.Marshal(transaction)
if err != nil https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
return &pb.Responsehttps://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpgStatus: pb.Response_FAILURE, Msg: []byte(fmt.Sprintf("Error sending transaction to local engine: %s", err))}
}
var response *pb.Response
msg := &pb.Messagehttps://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpgType: pb.Message_CHAIN_TRANSACTION, Payload: data, Timestamp: util.CreateUtcTimestamp()}
peerLogger.Debugf("Sending message %s with timestamp %v to local engine", msg.Type, msg.Timestamp)
response = p.engine.ProcessTransactionMsg(msg, transaction)
return response
}
8)从这里开端进入了consensus内部处理,在这里Consensus模块是独自剖析。
func (eng *EngineImpl) ProcessTransactionMsg(msg *pb.Message, tx *pb.Transaction) (response *pb.Response) https://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpg
err := eng.consenter.RecvMsg(msg, eng.peerEndpoint.ID)
}
画图阐明上述流程:
该图中没有表现的一点是在Devops Server创立的时分将PeerServer目标作为构造参数传入,而PeerServer创立的进程就是创立Engine的进程,也是加载Engine-handler的进程,而Engine-handler的完成在Consensus模块。图中直接从Devops Server 跳入Consensus模块有些突兀。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注