Fabric 1.4源码分析 - chaincode instantiate(7)endoser的endorseProposal过程

回顾到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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// endorse the proposal by calling the ESCC
func (e *Endorser) endorseProposal(_ context.Context, chainID string, txid string, signedProp *pb.SignedProposal, proposal *pb.Proposal, response *pb.Response, simRes []byte, event *pb.ChaincodeEvent, visibility []byte, ccid *pb.ChaincodeID, txsim ledger.TxSimulator, cd ccprovider.ChaincodeDefinition) (*pb.ProposalResponse, error) {
isSysCC := cd == nil
// 1) extract the name of the escc that is requested to endorse this chaincode, ie, "lscc" or system chaincodes
if isSysCC {
escc = "escc"
} else {
escc = cd.Endorsement()
}

// marshalling event bytes
if event != nil {
eventBytes, err = putils.GetBytesChaincodeEvent(event)
}

ctx := Context{
PluginName: escc,
Channel: chainID,
SignedProposal: signedProp,
ChaincodeID: ccid,
Event: eventBytes,
SimRes: simRes,
Response: response,
Visibility: visibility,
Proposal: proposal,
TxID: txid,
}
return e.s.EndorseWithPlugin(ctx)
}

// EndorseWithPlugin endorses the response with a plugin
func (pe *PluginEndorser) EndorseWithPlugin(ctx Context) (*pb.ProposalResponse, error) {
plugin, err := pe.getOrCreatePlugin(PluginName(ctx.PluginName), ctx.Channel)

prpBytes, err := proposalResponsePayloadFromContext(ctx)

endorsement, prpBytes, err := plugin.Endorse(prpBytes, ctx.SignedProposal)

resp := &pb.ProposalResponse{
Version: 1,
Endorsement: endorsement,
Payload: prpBytes,
Response: ctx.Response,
}
return resp, nil
}

// <默认的escc : github.com/hyperledger/fabric/core/handlers/endorsement/builtin/default_endorsement.go>
// Endorse signs the given payload(ProposalResponsePayload bytes), and optionally mutates it.
// Returns:
// The Endorsement: A signature over the payload, and an identity that is used to verify the signature
// The payload that was given as input (could be modified within this function)
// Or error on failure
func (e *DefaultEndorsement) Endorse(prpBytes []byte, sp *peer.SignedProposal) (*peer.Endorsement, []byte, error) {
signer, err := e.SigningIdentityForRequest(sp)

// serialize the signing identity
identityBytes, err := signer.Serialize()

// sign the concatenation of the proposal response and the serialized endorser identity with this endorser's key
signature, err := signer.Sign(append(prpBytes, identityBytes...))

endorsement := &peer.Endorsement{Signature: signature, Endorser: identityBytes}
return endorsement, prpBytes, nil
}

最后,返回的结构体为pb.ProposalResponse
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
"Version": 1, // 固定值
"Response": ${pb.Response}, // 上节instantiate(6)里从`chaincode/handler`返回的`pb.Response`. A response message indicating whether the endorsement of the action was successful
"Payload": ${peer.ProposalResponsePayload},
"Endorsement": ${peer.Endorsement} // 来源于`fabric/core/handlers/endorsement/plugin/plugin.go#Endorse`
}

// peer.ProposalResponsePayload
{
"Extension": ${&peer.ChaincodeAction}.byte[],
"ProposalHash": #putils.GetProposalHash1(proposal.hdr, proposal.Payload, ctx.Visibility)
}

// peer.ChaincodeAction
{
"Events": ${pb.chaincodeEvent}, // 上节instantiate(6)里从`chaincode/handler`返回的`pb.chaincodeEvent`
"Results": ${txSim.PubSimulationResults}, // 模拟结果,read-write set
"Response": ${pb.Response}, // 上节instantiate(6)里从`chaincode/handler`返回的`pb.Response`, 与外层的Response一致
"ChaincodeId": {"Name":"lscc","version":"latests"}
}

// peer.Endorsement
{
"Signature": #signer.Sign(append(prpBytes, identityBytes...)) // 将payload和dentity联合起来产生签名
"Endorser": #identityBytes = signer.Serialize()
}