回顾到endorser.go#SimulateProposal
,执行完callChaincode
后,回顾前面,在这里有两次调用chaincode,分别是lscc的Inovke和acc的Init,callChaincode
这里返回的是第一次调用的lscc的response。调用acc Init的结果只判断调用是否正常完成返回pb.ChaincodeMessage_COMPLETED
。这是因为在handleInit
里对初始化失败,即pb.Response.status
不等于200的统一返回pb.ChaincodeMessage_ERROR
,这点与Invoke的处理方式是不一样的。Invoke允许pb.ChaincodeMessage.Type
=pb.ChaincodeMessage_COMPLETED
,但是内层的pb.Response.status
不等于200. 若返回pb.ChaincodeMessage_ERROR
,则向上层返回error,最终返回&pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}
到peer chainncode instantiate...
这个命令的执行节点peer。
紧接着调用txsim.GetTxSimulationResults()
获取上节提到的lockbased_tx_simulator
的读写集合。先看下这个txsim
是如何传递的。首先初始化后在callChaincode
加入contextctxt = context.WithValue(ctxt, chaincode.TXSimulatorKey, txsim)
。之后在chaincode/handler
里构建TransactionContext
实体对象时将txsim从context取出,包裹进这个新建的TransactionContext对象内。这个对象前面有提及,是关联于chainID, txID
这两个存放于chaincode/handler.TXContexts.map[string]*TransactionContext
里。后面在chaincode/handler.go#handlerTranction
里调用txContext, err = h.isValidTxSim(msg.ChannelId, msg.Txid)}
也是以此取出该txsim,将读写结果放进读写集readwriteSet。
txsim.GetTxSimulationResults()
这里在返回前,先对读写集合按照key排序。这里包含pub和pri两部分数据,先关注pub部分。rwset这部分以后展开专题介绍。然后调用txsim.Done()
,签名初始化txsim时候提到获取了ledger的读锁,因此这里需要释放h.txmgr.commitRWLock.RUnlock()
。返回共有数据的读写集到endorser#ProcessProposal
。
第二步,背书模拟结果。主要是signer对payload进行签名,并且附上自身签名的identityBytes构造成response。然后这个resp就返回方法,通过grpc发送回调用方peer.
1 | // endorse the proposal by calling the ESCC |
最后,返回的结构体为
pb.ProposalResponse
1 | { |