hyperledger fabric 源碼解析-peer

來源:互聯網
上載者:User

0x00

在fabric中,peer是一個重要的二進位程式,其功能主要是提供peer相關的操作,關於peer的概念,可以參考官方文檔1和 官方文檔2,peer這個cli工具,作為一個用戶端,可以向區塊鏈網路(channel)發起peer相關從操作,這個命令包含很多的子命令,本文不會逐一介紹,這也不是本文的目的,本文主要是通過對peer源碼的分析,介紹一下fabric這個項目中,cli工具與服務端通訊的”套路“

0x01 準備工作

  • 一些golang的基本知識
  • rpc通訊的基本原理或者概念有所瞭解(瞭解grpc更好)
  • git有基本的認識

下載代碼

fabric的代碼目前在github上有鏡像,通過:

git clone https://github.com/hyperledger/fabric.git

就可以將代碼下到本地
代碼結構如下:

$ tree -L 1.├── bccsp├── build├── CHANGELOG.md├── ci.properties├── cmd├── CODE_OF_CONDUCT.md├── common                #公用工具源碼,例如configtxgen,cryptogen等├── CONTRIBUTING.md├── core                  # 主要代碼├── devenv├── discovery├── docker-env.mk├── docs├── events├── examples├── Gopkg.lock├── Gopkg.toml├── gossip├── gotools├── gotools.mk├── idemix            # ibm idemix密碼├── images├── integration├── LICENSE├── Makefile├── msp├── orderer             #orderer源碼├── peer                # peer命令源碼├── protos              # rpc源碼├── README.md├── release├── release_notes├── sampleconfig├── scripts├── settings.gradle├── si├── tox.ini├── unit-test└── vendor26 directories, 13 files

peer命令概覽

peer命令參數如下:

$ peer2018-06-18 09:39:18.382 UTC [msp] getMspConfig -> INFO 001 Loading NodeOUsUsage:  peer [flags]  peer [command]Available Commands:  chaincode   Operate a chaincode: install|instantiate|invoke|package|query|signpackage|upgrade|list.  channel     Operate a channel: create|fetch|join|list|update|signconfigtx|getinfo.  logging     Log levels: getlevel|setlevel|revertlevels.  node        Operate a peer node: start|status.  version     Print fabric peer version.Flags:  -h, --help                   help for peer      --logging-level string   Default logging level and overrides, see core.yaml for full syntax  -v, --version                Display current version of fabric peer serverUse "peer [command] --help" for more information about a command.2018-06-18 09:39:18.415 UTC [main] main -> INFO 002 Exiting.....

想要使用peer命令,可以直接通過 first network的 ./byfn.sh -m up 命令啟動一個樣本網路,然後通過docker exec -it peer0.org1.example.com bash 進入peer0的容器,然後執行 peer help就能看到上面的列印了

可以看到,peer一共有如下幾個子命令:

  • chaincode
  • channel
  • node
  • version

而當我們瀏覽peer目錄下的代碼結構是,發現恰好存在這幾個目錄:

$ tree -L 1          .├── chaincode├── channel├── clilogging├── common├── gossip├── main.go├── main_test.go├── mocks├── node├── testdata└── version9 directories, 2 files

很明顯,每一個子命令對應了要給目錄,而總的入口,則是main.go

main.go

現在,我們來看 main.go
首先,來個call graph:

output.png

可以看到,整個main.go中,主要是對viper和cobra的一些API的調用,其中,下面的代碼通過AddCommand將各個子目錄的代碼,以子命令形式添加了進來:

// 首先import 各個子目錄的包import (        // other imports    "github.com/hyperledger/fabric/peer/chaincode"    "github.com/hyperledger/fabric/peer/channel"    "github.com/hyperledger/fabric/peer/clilogging"    "github.com/hyperledger/fabric/peer/common"    "github.com/hyperledger/fabric/peer/node"    "github.com/hyperledger/fabric/peer/version")// 一些準備工作func main() {        // 環境變數初始化    mainCmd.AddCommand(version.Cmd())    mainCmd.AddCommand(node.Cmd())    mainCmd.AddCommand(chaincode.Cmd(nil))    mainCmd.AddCommand(clilogging.Cmd(nil))    mainCmd.AddCommand(channel.Cmd(nil))        // 其他的參數和配置解析        // 真正的命令執行    if mainCmd.Execute() != nil {        os.Exit(1)    }}

因此,要瞭解peer命令,其實就是需要搞懂底下各個子命令的實現

chaincode包

在瞭解了fabric命令的構造方式後(cobra+viper初始化命令,然後掛載子命令),我們再來以chaincode這個包作為一個例子,看看peer是怎麼與服務端通訊的,首先,再次看到,chaincode仍然有一系列的子命令:

  • install
  • instantiate
  • invoke
  • package
  • query
  • signpackage
  • upgrade
  • list
    不過,這些命令是直接在chaincode包中實現的,例如install命令,就對應了install.go
    我們開啟這個源碼檔案,看到入口就是:
func installCmd(cf *ChaincodeCmdFactory) *cobra.Command {    chaincodeInstallCmd = &cobra.Command{        Use:       "install",        Short:     fmt.Sprint(installDesc),        Long:      fmt.Sprint(installDesc),        ValidArgs: []string{"1"},        RunE: func(cmd *cobra.Command, args []string) error {            var ccpackfile string            if len(args) > 0 {                ccpackfile = args[0]            }            return chaincodeInstall(cmd, ccpackfile, cf)        },    }//...}

這裡,核心就是這個叫做RunE的入口,這是cobra的命令對象的入口函數,可以看到,這個屬性類型是一個函數,接受一個cobra.Command對象和參數字串,返回一個error對象,這個入口最終則調用了chaincodeInstall這個函數。

於是,我們來看看chaincodeInstall做了什麼:

func chaincodeInstall(cmd *cobra.Command, ccpackfile string, cf *ChaincodeCmdFactory) error {        // 準備工作    var err error    if cf == nil { //因此peer各個命令的cf參數都是nil,因此這裡是真正執行個體化cf的地方,                //InitCmdFactory函數裡會根據cmd.Name()來填充一個grpc用戶端,每個命令的grpc用戶端都是不一樣的        cf, err = InitCmdFactory(cmd.Name(), true, false)        if err != nil {            return err        }    }        // 準備工作    err = install(ccpackmsg, cf)    return err}//install the depspec to "peer.address"func install(msg proto.Message, cf *ChaincodeCmdFactory) error {    // 準備工作    proposalResponse, err := cf.EndorserClients[0].ProcessProposal(context.Background(), signedProp)    if err != nil {        return fmt.Errorf("Error endorsing %s: %s", chainFuncName, err)    }    if proposalResponse != nil {        logger.Infof("Installed remotely %v", proposalResponse)    }    return nil}

可以看到,chaincodeInstall最後調用了install函數,而該函數最後則是調用了cf.EndorserClients[0].ProcessProposal,這個函數的定義位於core/endorser/endorser.go,這是一個grpc的服務端介面,服務定義在protos/peer/peer.proto:

service Endorser {    rpc ProcessProposal(SignedProposal) returns (ProposalResponse) {}}

入參訊息定義在protos/peer/proposal.proto

message SignedProposal {    // The bytes of Proposal    bytes proposal_bytes = 1;  // Signaure over proposalBytes; this signature is to be verified against  // the creator identity contained in the header of the Proposal message  // marshaled as proposalBytes    bytes signature = 2;}

返回訊息定義在protos/peer/proposal_response.proto

message ProposalResponse {    // Version indicates message protocol version    int32 version = 1;    // Timestamp is the time that the message    // was created as  defined by the sender    google.protobuf.Timestamp timestamp = 2;    // A response message indicating whether the    // endorsement of the action was successful    Response response = 4;    // The payload of response. It is the bytes of ProposalResponsePayload    bytes payload = 5;    // The endorsement of the proposal, basically    // the endorser's signature over the payload    Endorsement endorsement = 6;}

這樣一來,我們就大致理清了peer命令的工作流程:

  1. 根據vip和cobra擷取配置資訊和命令列資訊
  2. 根據傳入的參數和配置,執行個體化各個命令的grpc用戶端
  3. 構造grpc訊息,並調用rpc方法,發送請求,並擷取訊息響應
  4. 根據響應,構造命令的輸出值

0x02 小結

本文簡單介紹了fabric的用戶端工具的代碼流程,歸納總結一下fabriccli的大致工作流程,可以看到,通過rpc通訊的方式,服務端和用戶端是一種非常鬆散的耦合關係,也可以為我們自己以後編寫相關cli程式提供一種思路。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.