1. 程式人生 > >區塊鏈教程Fabric1.0源代碼分析Peer(Endorser服務端)

區塊鏈教程Fabric1.0源代碼分析Peer(Endorser服務端)

java安裝 sys sch rop 版本 返回 The nal input

區塊鏈教程Fabric1.0源代碼分析Peer(Endorser服務端),2018年下半年,區塊鏈行業正逐漸褪去發展之初的浮躁、回歸理性,表面上看相關人才需求與身價似乎正在回落。但事實上,正是初期泡沫的漸退,讓人們更多的關註點放在了區塊鏈真正的技術之上。

Fabric 1.0源代碼筆記 之 Peer #EndorserServer(Endorser服務端)

1、EndorserServer概述

EndorserServer相關代碼在protos/peer、core/endorser目錄下。

  • protos/peer/peer.pb.go,EndorserServer接口定義。
  • core/endorser/endorser.go,EndorserServer接口實現,即Endorser結構體及方法,以及Endorser服務端ProcessProposal處理流程。

2、EndorserServer接口定義

2.1、EndorserServer接口定義

type EndorserServer interface {
????ProcessProposal(context.Context, *SignedProposal) (*ProposalResponse, error)
}
//代碼在protos/peer/peer.pb.go

2.2、gRPC相關實現

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

3、EndorserServer接口實現

3.1、Endorser結構體及方法

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

3.2、Endorser服務端ProcessProposal處理流程

Endorser服務端ProcessProposal處理流程,即func (e Endorser) ProcessProposal(ctx context.Context, signedProp pb.SignedProposal) (*pb.ProposalResponse, error)方法實現。

3.2.1、校驗SignedProposal合法性,並獲取ChannelHeader和SignatureHeader

//校驗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)代碼如下:

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

3.2.2、校驗是否系統鏈碼且提案不可調用,獲取chainID和TxId,獲取Ledger並校驗txid是否已存在,非系統鏈碼校驗提案權限(是否符合通道策略)

//校驗是否系統鏈碼且提案不可調用
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

3.2.3、獲取賬本的交易模擬器和歷史記錄查詢器,並模擬提案執行

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(鏈碼)

3.2.4、為提案背書,構造ProposalResponse並返回給Endorser客戶端

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

區塊鏈教程Fabric1.0源代碼分析Peer(Endorser服務端)