fabric源码解读【peer channel】:创建通道 peer channel join
fabric源码解读【peer channel】:加入通道peer channel join
命令
peer channel join -b mychannel.block -o orderer.suisui.com:7050
流程
源码分析
目录 /fabric/peer/channel/join.go
定义命令
//加入命令
func joinCmd(cf *ChannelCmdFactory) *cobra.Command {
joinCmd := &cobra.Command{
Use: "join",
Short: commandDescription,
Long: commandDescription,
RunE: func(cmd *cobra.Command, args []string) error {
//加入通道
return join(cmd, args, cf)
},
}
// 创世快区块路径 命令行中-b 表示 flags.StringVarP(&genesisBlockPath, "blockpath", "b", common.UndefinedParamValue, "Path to file containing genesis block")
flagList := []string{
"blockpath",
}
attachFlags(joinCmd, flagList)
return joinCmd
}
加入通道
//加入通道
func join(cmd *cobra.Command, args []string, cf *ChannelCmdFactory) error {
if genesisBlockPath == common.UndefinedParamValue {
return errors.New("Must supply genesis block path")
}
//初始化命令工厂,加入通道需要背书节点支持
var err error
if cf == nil {
cf, err = InitCmdFactory(EndorserRequired, OrdererNotRequired)
if err != nil {
return err
}
}
//执行加入通道
return executeJoin(cf)
}
执行加入通道
//执行加入通道
func executeJoin(cf *ChannelCmdFactory) (err error) {
//创建链码描述
spec, err := getJoinCCSpec()
if err != nil {
return err
}
//创建链码调用规范
invocation := &pb.ChaincodeInvocationSpec{ChaincodeSpec: spec}
creator, err := cf.Signer.Serialize()
if err != nil {
return fmt.Errorf("Error serializing identity for %s: %s", cf.Signer.GetIdentifier(), err)
}
//创建交易消息
var prop *pb.Proposal
prop, _, err = putils.CreateProposalFromCIS(pcommon.HeaderType_CONFIG, "", invocation, creator)
if err != nil {
return fmt.Errorf("Error creating proposal for join %s", err)
}
//对消息进行签名
var signedProp *pb.SignedProposal
signedProp, err = putils.GetSignedProposal(prop, cf.Signer)
if err != nil {
return fmt.Errorf("Error creating signed proposal %s", err)
}
// 发送消息到背书客户端请求加入通道
var proposalResp *pb.ProposalResponse
proposalResp, err = cf.EndorserClient.ProcessProposal(context.Background(), signedProp)
if err != nil {
return ProposalFailedErr(err.Error())
}
//验证相应结果
if proposalResp == nil {
return ProposalFailedErr("nil proposal response")
}
if proposalResp.Response.Status != 0 && proposalResp.Response.Status != 200 {
return ProposalFailedErr(fmt.Sprintf("bad proposal response %d", proposalResp.Response.Status))
}
logger.Info("Successfully submitted proposal to join channel")
return nil
}
背书节点处理
见后续背书节点处理章节,背书节点处理后,调用系统链码CSCC,执行CSCC invoke方法,arg[1]=JoinChain
CSCC链码处理
func (e *PeerConfiger) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
args := stub.GetArgs()
switch fname {
case JoinChain:
//加入通道
//校验参数
if args[1] == nil {
return shim.Error("Cannot join the channel <nil> configuration block provided")
}
//解析区块参数
block, err := utils.GetBlockFromBlockBytes(args[1])
if err != nil {
return shim.Error(fmt.Sprintf("Failed to reconstruct the genesis block, %s", err))
}
//获取链id
cid, err := utils.GetChainIDFromBlock(block)
if err != nil {
return shim.Error(fmt.Sprintf("\"JoinChain\" request failed to extract "+
"channel id from the block due to [%s]", err))
}
//校验区块
if err := validateConfigBlock(block); err != nil {
return shim.Error(fmt.Sprintf("\"JoinChain\" for chainID = %s failed because of validation "+
"of configuration block, because of %s", cid, err))
}
// 2. check local MSP Admins policy
// 校验访问策略
if err = e.policyChecker.CheckPolicyNoChannel(mgmt.Admins, sp); err != nil {
return shim.Error(fmt.Sprintf("\"JoinChain\" request failed authorization check "+
"for channel [%s]: [%s]", cid, err))
}
//加入通道
return joinChain(cid, block)
case GetConfigBlock:
...
}
//cscc加入通道
func joinChain(chainID string, block *common.Block) pb.Response {
// 创建本地账本对象 kvLedger
if err := peer.CreateChainFromBlock(block); err != nil {
return shim.Error(err.Error())
}
//初始化链id
peer.InitChain(chainID)
//创建区块事件
bevent, _, _, err := producer.CreateBlockEvents(block)
if err != nil {
cnflogger.Errorf("Error processing block events for block number [%d]: %s", block.Header.Number, err)
} else {
//发送区块事件
if err := producer.Send(bevent); err != nil {
cnflogger.Errorf("Channel [%s] Error sending block event for block number [%d]: %s", chainID, block.Header.Number, err)
}
}
//返回成功结果
return shim.Success(nil)
}