Fabric 1.0原始碼分析(35)Peer #EndorserServer(Endorser服務端)
# 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介面定義
```go
type EndorserServer interface {
ProcessProposal(context.Context, *SignedProposal) (*ProposalResponse, error)
}
//程式碼在protos/peer/peer.pb.go
```
### 2.2、gRPC相關實現
```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
```
## 3、EndorserServer介面實現
### 3.1、Endorser結構體及方法
```go
type Endorser struct {
policyChecker policy.PolicyChecker //策略檢查器
}
//程式碼在core/endorser/endorser.go
```
涉及方法如下:
```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)方法實現。
![](EndorserServer_ProcessProposal.png)
#### 3.2.1、校驗SignedProposal合法性,並獲取ChannelHeader和SignatureHeader
```go
//校驗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)程式碼如下:
```go
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是否已存在,非系統鏈碼校驗提案許可權(是否符合通道策略)
```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
```
#### 3.2.3、獲取賬本的交易模擬器和歷史記錄查詢器,並模擬提案執行
```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)程式碼如下:模擬提案執行。
```go
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)程式碼如下:為提案背書。
```go
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(鏈碼)](../chaincode/README.md)
#### 3.2.4、為提案背書,構造ProposalResponse並返回給Endorser客戶端
```go
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)程式碼如下:
```go
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
```
網址:http://www.qukuailianxueyuan.io/
欲領取造幣技術與全套虛擬機器資料
區塊鏈技術交流QQ群:756146052 備註:CSDN
尹成學院微信:備註:CSDN
網址:http://www.qukuailianxueyuan.io/
欲領取造幣技術與全套虛擬機器資料
區塊鏈技術交流QQ群:756146052 備註:CSDN
尹成學院微信:備註:CSDN
相關文章
- Fabric 1.0原始碼分析(36) Peer #EndorserClient(Endorser客戶端)原始碼client客戶端
- Fabric 1.0原始碼分析(31) Peer原始碼
- Fabric 1.0原始碼分析(37) Peer #DeliverClient(Deliver客戶端)原始碼client客戶端
- Fabric 1.0原始碼分析(38) Peer #BroadcastClient(Broadcast客戶端)原始碼ASTclient客戶端
- Fabric 1.0原始碼分析(32) Peer #peer node start命令實現原始碼
- Fabric 1.0原始碼分析(30) Orderer #BroadcastServer(Broadcast服務端)原始碼ASTServer服務端
- Fabric 1.0原始碼分析(33) Peer #peer channel命令及子命令實現原始碼
- Fabric 1.0原始碼分析(34) Peer #peer chaincode命令及子命令實現原始碼AI
- Fabric 1.0原始碼分析(13)events(事件服務)原始碼事件
- Fabric 1.0原始碼分析(32)Peer #peer根命令入口及載入子命令原始碼
- Fabric 1.0原始碼分析(16)gossip(流言演算法) #GossipServer(Gossip服務端)原始碼Go演算法Server服務端
- Fabric 1.0原始碼分析(25) Orderer原始碼
- Fabric 1.0原始碼分析(1)BCCSP(區塊鏈加密服務提供者)原始碼區塊鏈加密
- Fabric 1.0原始碼分析(24)MSP(成員關係服務提供者)原始碼
- Fabric 1.0原始碼分析(3)Chaincode(鏈碼)原始碼AI
- Fabric 1.0原始碼分析(40) Proposal(提案)原始碼
- 區塊鏈教程Fabric1.0原始碼分析流言演算法Gossip服務端二-兄弟連區塊鏈原始碼演算法Go服務端
- Fabric 1.0原始碼分析(14) flogging(Fabric日誌系統)原始碼
- Fabric 1.0原始碼分析(18) Ledger(賬本)原始碼
- Fabric 1.0原始碼分析(43) Tx(Transaction 交易)原始碼
- Fabric 1.0原始碼分析(47)Fabric 1.0.4 go程式碼量統計原始碼Go
- Fabric 1.0原始碼分析(42)scc(系統鏈碼)原始碼
- Fabric 1.0原始碼分析(26)Orderer #ledger(Orderer Ledger)原始碼
- Fabric 1.0原始碼分析(39) policy(背書策略)原始碼
- Fabric 1.0原始碼分析(45)gRPC(Fabric中註冊的gRPC Service)原始碼RPC
- 區塊鏈教程Fabric1.0原始碼分析流言演算法Gossip服務端一兄弟連區塊鏈教程區塊鏈原始碼演算法Go服務端
- Fabric 1.0原始碼分析(10)consenter(共識外掛)原始碼
- Fabric 1.0原始碼分析(15)gossip(流言演算法)原始碼Go演算法
- Fabric 1.0原始碼分析(23)LevelDB(KV資料庫)原始碼資料庫
- Fabric 1.0原始碼分析(44)Tx #RWSet(讀寫集)原始碼
- Fabric 1.0原始碼分析(17)gossip(流言演算法) #deliverclient(deliver客戶端)原始碼Go演算法client客戶端
- Fabric 1.0原始碼分析(5)Chaincode(鏈碼)體系總結原始碼AI
- Fabric 1.0原始碼分析(6)configtx(配置交易) #ChannelConfig(通道配置)原始碼
- Fabric 1.0原始碼分析(20) Ledger #idStore(ledgerID資料庫)原始碼資料庫
- Fabric 1.0原始碼分析(29) Orderer #multichain(多鏈支援包)原始碼AI
- Fabric 1.0原始碼分析(41)putils(protos/utils工具包)原始碼
- Fabric1.4原始碼解析:Peer節點加入通道原始碼
- Fabric 1.0原始碼分析(2) blockfile(區塊檔案儲存)原始碼BloC