0x00
In fabric, peer is an important binary program, its function is mainly to provide peer
related operations, regarding peer concept, can refer to official Document 1 and Official Document 2, peer
this CLI tool, as a client, can be launched to the Blockchain Network ( channel
) peer
related from the operation, this command contains a lot of sub-commands, this article will not be introduced, this is not the purpose of this article, this article is mainly through the analysis of the peer
source code, introduction of fabric
the project, cli
tools and service-side communication "routines"
0x01 preparatory work
- Some
golang
of the basic knowledge
rpc
knowledge of the basic principles or concepts of communication ( grpc
better understanding)
git
have a basic understanding of
Download code
fabric
The code currently github
has an image on it, by:
git clone https://github.com/hyperledger/fabric.git
You can put the code down to the local
The code structure is as follows:
$ 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 Command Overview
The peer command parameters are as follows:
$ peer2018-06-18 09:39:18.382 UTC [MSP] Getmspconfig-INFO 001 Loading Nodeoususage:peer [F Lags] Peer [command]available commands:chaincode Operate a Chaincode:install|instantiate|invoke|package|query|signpa Ckage|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 information about a command.2018-06-18 09:39:18.415 UTC [main] Main--INFO 002 Exiting ...
To use peer
a command, you can start a sample network directly from a command on first network ./byfn.sh -m up
, then go through the docker exec -it peer0.org1.example.com bash
Peer0 container and then execute peer help
to see the print
As you can see, peer
there are a total of several subcommands:
- Chaincode
- Channel
- Node
- Version
And when we browse the peer
code structure under the directory, we find that there are just a few directories:
$ tree -L 1 .├── chaincode├── channel├── clilogging├── common├── gossip├── main.go├── main_test.go├── mocks├── node├── testdata└── version9 directories, 2 files
It is clear that each subcommand corresponds to the directory, and the total entry ismain.go
Main.go
Now, let's see Main.go.
First, call graph:
Output.png
As you can see, the entire main.go is primarily called for some API calls to Viper and Cobra, where the following code adds the code for each subdirectory by AddCommand, in the form of a subcommand:
// 首先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) }}
Therefore, in order to understand the peer
command, it is necessary to understand the implementation of the sub-commands below
Chaincode Bag
After knowing how the fabric
command was constructed ( cobra+viper
initialize the command and then mount the subcommand), let's take chaincode
this package as an example to see peer
how it communicates with the server, first, again, chaincode
there are still a series of subcommands:
- Install
- Instantiate
- Invoke
- Package
- Query
- Signpackage
- Upgrade
- List
However, these commands are implemented directly in the Chaincode package, such as install
commands, which correspond to the Install.go
We open this source file and see that the entrance is:
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) }, }//...}
Here, the core is this called RunE
the portal, this is cobra
the Command object's entry function, you can see that this property type is a function, accept a Cobra.command object and parameter string, return an Error object, the portal finally called the chaincodeInstall
function.
So, let's look at what we've chaincodeInstall
done:
func chaincodeinstall (cmd *cobra. Command, ccpackfile string, cf *chaincodecmdfactory) error {//prepare to work Var err error if CF = nil {//So peer each life The CF parameters are nil, so here is where the CF is really instantiated,//initcmdfactory function will be based on Cmd.name () to populate a GRPC client, each command GRPC client is not the same CF, err = Initcmdfactory (cmd). Name (), True, false) if err! = Nil {return err}}//preparation Work Err = Install (ccpackmsg, CF) return Err}//install the Depspec to "peer.address" Func Install (msg proto. Message, cf *chaincodecmdfactory) error {//prep work 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}
As you can see, the function is finally called, and the function chaincodeInstall
install
is finally called, and the definition of this cf.EndorserClients[0].ProcessProposal
function is located core/endorser/endorser.go
, which is a GRPC server interface, and the service is defined in the protos/peer/peer.proto
following:
service Endorser { rpc ProcessProposal(SignedProposal) returns (ProposalResponse) {}}
The incoming parameter message is defined in theprotos/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;}
The return message definition is defined inprotos/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;}
In this way, we have roughly cleared the peer
workflow of the command:
- Get configuration information and command line information based on VIP and Cobra
- Instantiate the GRPC client for each command based on the parameters and configuration passed in
- Constructs a GRPC message and calls the RPC method, sends the request, and gets the message response
- Constructs the output value of the command according to the response
0x02 Summary
This article provides a brief introduction to the code flow for the client tools of fabric
, summarizes the approximate workflow of CLI in fabric
, and you can see how RPC communication is The server and client are a very loosely coupled relationship, and can provide a way for us to write the relevant CLI program ourselves later.