兄弟連區塊鏈教程Fabric1.0源代碼分析Peer(Endorser服務端),2018年下半年,區塊鏈行業正逐漸褪去發展之初的浮躁、迴歸理性,表面上看相關人才需求與身價彷佛正在回落。但事實上,正是初期泡沫的漸退,讓人們更多的關注點放在了區塊鏈真正的技術之上。ide
EndorserServer相關代碼在protos/peer、core/endorser目錄下。區塊鏈
type EndorserServer interface { ProcessProposal(context.Context, *SignedProposal) (*ProposalResponse, error) } //代碼在protos/peer/peer.pb.go
var _Endorser_serviceDesc = grpc.ServiceDesc{ ServiceName: "protos.Endorser", HandlerType: (*EndorserServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "ProcessProposal", Handler: _Endorser_ProcessProposal_Handler, }, }, Streams: []grpc.StreamDesc{}, Metadata: "peer/peer.proto", } func RegisterEndorserServer(s *grpc.Server, srv EndorserServer) { s.RegisterService(&_Endorser_serviceDesc, srv) } func _Endorser_ProcessProposal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(SignedProposal) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(EndorserServer).ProcessProposal(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: "/protos.Endorser/ProcessProposal", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(EndorserServer).ProcessProposal(ctx, req.(*SignedProposal)) } return interceptor(ctx, in, info, handler) } //代碼在protos/peer/peer.pb.go
type Endorser struct { policyChecker policy.PolicyChecker //策略檢查器 } //代碼在core/endorser/endorser.go
涉及方法以下:測試
//構造Endorser func NewEndorserServer() pb.EndorserServer //執行提案 func (e *Endorser) ProcessProposal(ctx context.Context, signedProp *pb.SignedProposal) (*pb.ProposalResponse, error) //檢查SignedProposal是否符合通道策略,調用e.policyChecker.CheckPolicy() func (e *Endorser) checkACL(signedProp *pb.SignedProposal, chdr *common.ChannelHeader, shdr *common.SignatureHeader, hdrext *pb.ChaincodeHeaderExtension) error //檢查Escc和Vscc,暫未實現 func (*Endorser) checkEsccAndVscc(prop *pb.Proposal) error //獲取帳本的交易模擬器,調用peer.GetLedger(ledgername).NewTxSimulator() func (*Endorser) getTxSimulator(ledgername string) (ledger.TxSimulator, error) //獲取帳本歷史交易查詢器,調用peer.GetLedger(ledgername).NewHistoryQueryExecutor() func (*Endorser) getHistoryQueryExecutor(ledgername string) (ledger.HistoryQueryExecutor, error) //執行鏈碼 func (e *Endorser) callChaincode(ctxt context.Context, chainID string, version string, txid string, signedProp *pb.SignedProposal, prop *pb.Proposal, cis *pb.ChaincodeInvocationSpec, cid *pb.ChaincodeID, txsim ledger.TxSimulator) (*pb.Response, *pb.ChaincodeEvent, error) func (e *Endorser) disableJavaCCInst(cid *pb.ChaincodeID, cis *pb.ChaincodeInvocationSpec) error //經過調用chaincode來模擬提案 func (e *Endorser) simulateProposal(ctx context.Context, chainID string, txid string, signedProp *pb.SignedProposal, prop *pb.Proposal, cid *pb.ChaincodeID, txsim ledger.TxSimulator) (*ccprovider.ChaincodeData, *pb.Response, []byte, *pb.ChaincodeEvent, error) //從LSCC獲取鏈碼數據 func (e *Endorser) getCDSFromLSCC(ctx context.Context, chainID string, txid string, signedProp *pb.SignedProposal, prop *pb.Proposal, chaincodeID string, txsim ledger.TxSimulator) (*ccprovider.ChaincodeData, error) //提案背書 func (e *Endorser) endorseProposal(ctx 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.ChaincodeData) (*pb.ProposalResponse, error) //提交模擬交易,僅測試使用 func (e *Endorser) commitTxSimulation(proposal *pb.Proposal, chainID string, signer msp.SigningIdentity, pResp *pb.ProposalResponse, blockNumber uint64) error //代碼在core/endorser/endorser.go
Endorser服務端ProcessProposal處理流程,即func (e Endorser) ProcessProposal(ctx context.Context, signedProp pb.SignedProposal) (*pb.ProposalResponse, error)方法實現。ui
//校驗SignedProposal合法性 prop, hdr, hdrExt, err := validation.ValidateProposalMessage(signedProp) //獲取ChannelHeader chdr, err := putils.UnmarshalChannelHeader(hdr.ChannelHeader) //獲取SignatureHeader shdr, err := putils.GetSignatureHeader(hdr.SignatureHeader) //代碼在core/endorser/endorser.go
validation.ValidateProposalMessage(signedProp)代碼以下:code
func ValidateProposalMessage(signedProp *pb.SignedProposal) (*pb.Proposal, *common.Header, *pb.ChaincodeHeaderExtension, error) { prop, err := utils.GetProposal(signedProp.ProposalBytes) //獲取type Proposal struct hdr, err := utils.GetHeader(prop.Header) //獲取Proposal.Header chdr, shdr, err := validateCommonHeader(hdr) //校驗Proposal.Header //檢查來自建立者的簽名 err = checkSignatureFromCreator(shdr.Creator, signedProp.Signature, signedProp.ProposalBytes, chdr.ChannelId) //校驗交易TxID,TxID由Nonce和Creator構成 err = utils.CheckProposalTxID( chdr.TxId, //ChannelHeader.TxId shdr.Nonce, //SignatureHeader.Nonce shdr.Creator) //SignatureHeader.Creator switch common.HeaderType(chdr.Type) { case common.HeaderType_CONFIG: fallthrough case common.HeaderType_ENDORSER_TRANSACTION: //校驗ChaincodeHeaderExtension chaincodeHdrExt, err := validateChaincodeProposalMessage(prop, hdr) return prop, hdr, chaincodeHdrExt, err default: return nil, nil, nil, fmt.Errorf("Unsupported proposal type %d", common.HeaderType(chdr.Type)) } } //代碼在core/common/validation/msgvalidation.go
//校驗是否系統鏈碼且提案不可調用 if syscc.IsSysCCAndNotInvokableExternal(hdrExt.ChaincodeId.Name) { //若是是系統鏈碼且提案不可調用 } //獲取chainID,即ChannelId chainID := chdr.ChannelId //獲取交易TxId txid := chdr.TxId if chainID != "" { //獲取Ledger lgr := peer.GetLedger(chainID) //校驗txid是否已存在 _, err := lgr.GetTransactionByID(txid) //非系統鏈碼校驗提案權限(是否符合通道策略) if !syscc.IsSysCC(hdrExt.ChaincodeId.Name) { err = e.checkACL(signedProp, chdr, shdr, hdrExt) } } //代碼在core/endorser/endorser.go
var txsim ledger.TxSimulator var historyQueryExecutor ledger.HistoryQueryExecutor if chainID != "" { //獲取帳本的交易模擬器 txsim, err = e.getTxSimulator(chainID) //獲取歷史記錄查詢器 historyQueryExecutor, err = e.getHistoryQueryExecutor(chainID) //HistoryQueryExecutorKey key = "historyqueryexecutorkey" //context.WithValue,將Key與對象創建關係 ctx = context.WithValue(ctx, chaincode.HistoryQueryExecutorKey, historyQueryExecutor) } //模擬提案執行 cd, res, simulationResult, ccevent, err := e.simulateProposal(ctx, chainID, txid, signedProp, prop, hdrExt.ChaincodeId, txsim) //代碼在core/endorser/endorser.go
e.simulateProposal(ctx, chainID, txid, signedProp, prop, hdrExt.ChaincodeId, txsim)代碼以下:模擬提案執行。對象
func (e *Endorser) simulateProposal(ctx context.Context, chainID string, txid string, signedProp *pb.SignedProposal, prop *pb.Proposal, cid *pb.ChaincodeID, txsim ledger.TxSimulator) (*ccprovider.ChaincodeData , *pb.Response, []byte, *pb.ChaincodeEvent, error) { //獲取ChaincodeInvocationSpec cis, err := putils.GetChaincodeInvocationSpec(prop) //禁用Java安裝、實例化和當即升級 err = e.disableJavaCCInst(cid, cis) //檢查Escc和Vscc,暫未實現 err = e.checkEsccAndVscc(prop) var cdLedger *ccprovider.ChaincodeData var version string if !syscc.IsSysCC(cid.Name) { //非系統鏈碼 //獲取鏈碼數據ChaincodeData cdLedger, err = e.getCDSFromLSCC(ctx, chainID, txid, signedProp, prop, cid.Name, txsim) //獲取鏈碼數據版本 version = cdLedger.Version //檢查鏈碼實例化策略 err = ccprovider.CheckInsantiationPolicy(cid.Name, version, cdLedger) } else { version = util.GetSysCCVersion() //獲取系統鏈碼版本 } var simResult []byte var res *pb.Response var ccevent *pb.ChaincodeEvent //執行鏈碼 res, ccevent, err = e.callChaincode(ctx, chainID, version, txid, signedProp, prop, cis, cid, txsim) if txsim != nil { //獲取交易模擬結果 simResult, err = txsim.GetTxSimulationResults() } return cdLedger, res, simResult, ccevent, nil } //代碼在core/endorser/endorser.go
e.endorseProposal(ctx, chainID, txid, signedProp, prop, res, simulationResult, ccevent, hdrExt.PayloadVisibility, hdrExt.ChaincodeId, txsim, cd)代碼以下:爲提案背書。教程
func (e *Endorser) callChaincode(ctxt context.Context, chainID string, version string, txid string, signedProp *pb.SignedProposal, prop *pb.Proposal, cis *pb.ChaincodeInvocationSpec, cid *pb.ChaincodeID, txsim ledger.TxSimulator) (*pb.Response, *pb.ChaincodeEvent, error) { var err error var res *pb.Response var ccevent *pb.ChaincodeEvent if txsim != nil { //TXSimulatorKey key = "txsimulatorkey",key與對象創建關係 ctxt = context.WithValue(ctxt, chaincode.TXSimulatorKey, txsim) } scc := syscc.IsSysCC(cid.Name) //是否系統鏈碼 cccid := ccprovider.NewCCContext(chainID, cid.Name, version, txid, scc, signedProp, prop) //執行鏈碼 res, ccevent, err = chaincode.ExecuteChaincode(ctxt, cccid, cis.ChaincodeSpec.Input.Args) //若是是生命週期管理系統鏈碼,而且參數爲實例化或升級 if cid.Name == "lscc" && len(cis.ChaincodeSpec.Input.Args) >= 3 && (string(cis.ChaincodeSpec.Input.Args[0]) == "deploy" || string(cis.ChaincodeSpec.Input.Args[0]) == "upgrade") { var cds *pb.ChaincodeDeploymentSpec //獲取ChaincodeDeploymentSpec cds, err = putils.GetChaincodeDeploymentSpec(cis.ChaincodeSpec.Input.Args[2]) //待實例化或升級的鏈碼執行實例化或升級 cccid = ccprovider.NewCCContext(chainID, cds.ChaincodeSpec.ChaincodeId.Name, cds.ChaincodeSpec.ChaincodeId.Version, txid, false, signedProp, prop) _, _, err = chaincode.Execute(ctxt, cccid, cds) } return res, ccevent, err } //代碼在core/endorser/endorser.go
Chaincode更詳細內容,參考:Fabric 1.0源代碼筆記 之 Chaincode(鏈碼)接口
var pResp *pb.ProposalResponse //爲提案背書,即調取escc系統鏈碼 pResp, err = e.endorseProposal(ctx, chainID, txid, signedProp, prop, res, simulationResult, ccevent, hdrExt.PayloadVisibility, hdrExt.ChaincodeId, txsim, cd) pResp.Response.Payload = res.Payload return pResp, nil //代碼在core/endorser/endorser.go
e.endorseProposal(ctx, chainID, txid, signedProp, prop, res, simulationResult, ccevent, hdrExt.PayloadVisibility, hdrExt.ChaincodeId, txsim, cd)代碼以下:生命週期
func (e *Endorser) endorseProposal(ctx 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.ChaincodeData) (*pb.ProposalResponse, error) { isSysCC := cd == nil var escc string if isSysCC { escc = "escc" } else { escc = cd.Escc } var err error var eventBytes []byte if event != nil { eventBytes, err = putils.GetBytesChaincodeEvent(event) } resBytes, err := putils.GetBytesResponse(response) if isSysCC { ccid.Version = util.GetSysCCVersion() } else { ccid.Version = cd.Version } ccidBytes, err := putils.Marshal(ccid) args := [][]byte{[]byte(""), proposal.Header, proposal.Payload, ccidBytes, resBytes, simRes, eventBytes, visibility} version := util.GetSysCCVersion() ecccis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG, ChaincodeId: &pb.ChaincodeID{Name: escc}, Input: &pb.ChaincodeInput{Args: args}}} //執行escc系統鏈碼 res, _, err := e.callChaincode(ctx, chainID, version, txid, signedProp, proposal, ecccis, &pb.ChaincodeID{Name: escc}, txsim) prBytes := res.Payload pResp, err := putils.GetProposalResponse(prBytes) return pResp, nil } //代碼在core/endorser/endorser.go
感謝關注兄弟連區塊鏈教程分享!ci