以Invoke Transaction的构造为例. 分析基于v6.0版本的代码.
构造一个Transaction对象的流程
Transaction
对象定义在fabric/protos/fabric.pb.go
中,代码如下:
|
|
构造一个Transcation对象的关键在于如何填充Payload字段. 对于Type为Invoke的Transaction来说, Payload字段是一个Marshal过的ChaincodeInvationSpec
对象, 该对象在fabric/protos/chaincode.pb.go
中定义, 代码如下:
|
|
里面的ChaincodeSpec在同一个文件下面:
|
|
其中最核心的字段为CTorMsg
和ChaincodeId
. ChiancodeId为chaincode的路径,CTorMsg是一个指向ChaincodeInput对象的指针, 而ChiancodeInput就是调用Chaincode时指定的函数名以及参数.
因此构造一个Invoke类型的Transaction的关键步骤为:
|
|
peer客户端是如何把命令行参数构造成相应Transaction对象的
peer使用了cobra框架, 对应chaincode子命令的相应定义在fabric/peer/chaincode/chaincode.go
. 通过分析发现与invoke操作挂钩的是fabric/peer/chaincode/invoke.go
里面的chaincodeInvoke
, 而这个函数又转而直接调用了fabric/peer/chaincode/common.go
里的chaincodeInvokeOrQuery
. 关键的部分从这里开始.
函数先是调用了getChaincodeSpecification
来构造一个ChaincodeSpec
.
跟到getChaincodeSpecification
里, 可以看到在这里ChaincodeSpec
是如何被填充的:
|
|
其中的chaincodeCtorJSON
等变量就是从命令行传入的JSON格式的参数, 这个函数把这些参数Unmarshal之后填入了目标chaincodeSpec中.
得到chaincodeSpec
之后,回到chaincodeInvokeOrQuery
,可以看到这个chaincodeSpec
被用以勾造了一个ChaincodeInvocationSpec
:
|
|
按照上一节说的构造顺序, 接下来只要把这个ChaincodeInvocationSpec
给marshal了然后扔进一个Transaction
里就大功告成了. 而这个动作是在fabric/core/devops.go
的createExecTx
函数中完成的(这里实际上省略了很长一段调用链的分析, 大概流程为: grpc调用invoke方法->invoke_handler->devopsServer.invoke->createExecTx).
到了createExecTx
思路实际上就很清晰了, 里面有关键性的一行:
|
|
其中uuid是用util.GenerateIdWithAlg
由spec中的CtorMsg
算出来的, t就是Transaction类型.也就是说, pb.NewChaincodeExecute
完成了最终的Transaction组装.它位于fabridc/protos/transaction.go
, 代码如下:
|
|
至此, 整个流程完成.