zoukankan      html  css  js  c++  java
  • 菜鸟系列Fabric源码学习 — 创建通道

    通道创建源码解析

    1. 与通道创建相关配置及操作命令

    主要是configtx.yaml。通过应用通道的profile生成创建通道的配置文件。

        TwoOrgsChannel:
            Consortium: SampleConsortium
            <<: *ChannelDefaults
            Application:
                <<: *ApplicationDefaults
                Organizations:
                    - *Org1
                    - *Org2
                Capabilities:
                    <<: *ApplicationCapabilities
    

    接着在客户端执行下列命令创建通道。

    peer channel create -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/channel.tx --tls true --cafile $ORDERER_CA
    

    peer channel create命令:

    Create a channel and write the genesis block to a file.
    
    Usage:
      peer channel create [flags]
    
    Flags:
      -c, --channelID string     In case of a newChain command, the channel ID to create. It must be all lower case, less than 250 characters long and match the regular expression: [a-z][a-z0-9.-]*
      -f, --file string          Configuration transaction file generated by a tool such as configtxgen for submitting to orderer
      -h, --help                 help for create
          --outputBlock string   The path to write the genesis block for the channel. (default ./<channelID>.block)
      -t, --timeout duration     Channel creation timeout (default 10s)
    
    Global Flags:
          --cafile string                       Path to file containing PEM-encoded trusted certificate(s) for the ordering endpoint
          --certfile string                     Path to file containing PEM-encoded X509 public key to use for mutual TLS communication with the orderer endpoint
          --clientauth                          Use mutual TLS when communicating with the orderer endpoint
          --connTimeout duration                Timeout for client to connect (default 3s)
          --keyfile string                      Path to file containing PEM-encoded private key to use for mutual TLS communication with the orderer endpoint
      -o, --orderer string                      Ordering service endpoint
          --ordererTLSHostnameOverride string   The hostname override to use when validating the TLS connection to the orderer.
          --tls                                 Use TLS when communicating with the orderer endpoint
    

    2.创建通道命令执行流程

    首先,在peer main.go文件的main()方法中,添加peer相关操作命令。

    	mainCmd.AddCommand(version.Cmd())
    	mainCmd.AddCommand(node.Cmd())
    	mainCmd.AddCommand(chaincode.Cmd(nil))
    	mainCmd.AddCommand(clilogging.Cmd(nil))
    	mainCmd.AddCommand(channel.Cmd(nil))
    

    而channel相关命令代码为:

    // Cmd returns the cobra command for Node
    func Cmd(cf *ChannelCmdFactory) *cobra.Command {
    	AddFlags(channelCmd)
    
    	channelCmd.AddCommand(createCmd(cf))
    	channelCmd.AddCommand(fetchCmd(cf))
    	channelCmd.AddCommand(joinCmd(cf))
    	channelCmd.AddCommand(listCmd(cf))
    	channelCmd.AddCommand(updateCmd(cf))
    	channelCmd.AddCommand(signconfigtxCmd(cf))
    	channelCmd.AddCommand(getinfoCmd(cf))
    
    	return channelCmd
    }
    

    其中,创建通道调用的接口为create(cmd, args, cf)

    func createCmd(cf *ChannelCmdFactory) *cobra.Command {
    	createCmd := &cobra.Command{
    		Use:   "create",
    		Short: "Create a channel",
    		Long:  "Create a channel and write the genesis block to a file.",
    		RunE: func(cmd *cobra.Command, args []string) error {
    			return create(cmd, args, cf)
    		},
    	}
    	flagList := []string{
    		"channelID",
    		"file",
    		"outputBlock",
    		"timeout",
    	}
    	attachFlags(createCmd, flagList)
    
    	return createCmd
    }
    

    上述为peer创建通道的命令构建流程。具体创建通道实现为create()方法。

    1. 如果通道id为"",则报错
    2. 如果不存在CmdFactory,则初始化CmdFactory
    3. 将CmdFactory传入,调用executeCreate()方法,执行创建通道逻辑
    func create(cmd *cobra.Command, args []string, cf *ChannelCmdFactory) error {
    	// the global chainID filled by the "-c" command
    	if channelID == common.UndefinedParamValue {
    		return errors.New("must supply channel ID")
    	}
    
    	// Parsing of the command line is done so silence cmd usage
    	cmd.SilenceUsage = true
    
    	var err error
    	if cf == nil {
    		cf, err = InitCmdFactory(EndorserNotRequired, PeerDeliverNotRequired, OrdererRequired)
    		if err != nil {
    			return err
    		}
    	}
    	return executeCreate(cf)
    }
    

    现在看看InitCmdFactory()方法:

    // InitCmdFactory init the ChannelCmdFactory with clients to endorser and orderer according to params
    func InitCmdFactory(isEndorserRequired, isPeerDeliverRequired, isOrdererRequired bool) (*ChannelCmdFactory, error) {
        // 只从peer或者orderer其中一个获取区块
    	if isPeerDeliverRequired && isOrdererRequired {
    		// this is likely a bug during development caused by adding a new cmd
    		return nil, errors.New("ERROR - only a single deliver source is currently supported")
    	}
    
    	var err error
    	cf := &ChannelCmdFactory{}
        // 获取默认签名(默认peer)
    	cf.Signer, err = common.GetDefaultSignerFnc()
    	if err != nil {
    		return nil, errors.WithMessage(err, "error getting default signer")
    	}
    
    	cf.BroadcastFactory = func() (common.BroadcastClient, error) {
    	    // 获取BroadcastClient
    		return common.GetBroadcastClientFnc()
    	}
    
    	// for join and list, we need the endorser as well
    	if isEndorserRequired {
    	    //创建背书客户端
    		// creating an EndorserClient with these empty parameters will create a
    		// connection using the values of "peer.address" and
    		// "peer.tls.rootcert.file"
    		cf.EndorserClient, err = common.GetEndorserClientFnc(common.UndefinedParamValue, common.UndefinedParamValue)
    		if err != nil {
    			return nil, errors.WithMessage(err, "error getting endorser client for channel")
    		}
    	}
    
    	// for fetching blocks from a peer
        // NewDeliverClientForPeer creates a new DeliverClient from a PeerClient
    	if isPeerDeliverRequired {
    		cf.DeliverClient, err = common.NewDeliverClientForPeer(channelID)
    		if err != nil {
    			return nil, errors.WithMessage(err, "error getting deliver client for channel")
    		}
    	}
    
    	// for create and fetch, we need the orderer as well
    	if isOrdererRequired {
    		if len(strings.Split(common.OrderingEndpoint, ":")) != 2 {
    			return nil, errors.Errorf("ordering service endpoint %s is not valid or missing", common.OrderingEndpoint)
    		}
    		cf.DeliverClient, err = common.NewDeliverClientForOrderer(channelID)
    		if err != nil {
    			return nil, err
    		}
    	}
    	logger.Infof("Endorser and orderer connections initialized")
    	return cf, nil
    }
    

    总结:创建通道,获取区块/deliver源只能是orderer,并且不需要创建背书客户端。要求从orderer创建deliver client。

    3.通道创建具体实现

    executeCreate()方法,其中创建通道也是一个交易,基于ChannelCmdFactory cf发送创建通道交易,然后获取创世块并保存

    1. 发送创建通道交易
    2. 获取区块
    3. proto序列化并保存
    func executeCreate(cf *ChannelCmdFactory) error {
        //发送创建通道的Transaction到Order节点
    	err := sendCreateChainTransaction(cf)
    	if err != nil {
    		return err
    	}
        //获取该通道内的创世区块(该过程在Order节点共识完成之后)
    	block, err := getGenesisBlock(cf)
    	if err != nil {
    		return err
    	}
        //序列化创世区块
    	b, err := proto.Marshal(block)
    	if err != nil {
    		return err
    	}
        
    	file := channelID + ".block"
    	if outputBlock != common.UndefinedParamValue {
    		file = outputBlock
    	}
    	//将创世区块保存到本地
    	err = ioutil.WriteFile(file, b, 0644)
    	if err != nil {
    		return err
    	}
    
    	return nil
    }
    

    3.1 发送创建通道交易

    • 查看交易数据结构
    // Envelope wraps a Payload with a signature so that the message may be authenticated
    type Envelope struct {
    	// A marshaled Payload
    	// 序列化后的相关信息
    	Payload []byte `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"`
    	// A signature by the creator specified in the Payload header
    	// 签名
    	Signature            []byte   `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"`
    	XXX_NoUnkeyedLiteral struct{} `json:"-"`
    	XXX_unrecognized     []byte   `json:"-"`
    	XXX_sizecache        int32    `json:"-"`
    }
    

    发送交易方法代码:

    func sendCreateChainTransaction(cf *ChannelCmdFactory) error {
    	var err error
    	var chCrtEnv *cb.Envelope
        // 如果存在tx文件,则从tx文件生成创建通道交易
    	if channelTxFile != "" {
    		if chCrtEnv, err = createChannelFromConfigTx(channelTxFile); err != nil {
    			return err
    		}
    	} else {
    	    // 不存在,则利用默认模版生成
    		if chCrtEnv, err = createChannelFromDefaults(cf); err != nil {
    			return err
    		}
    	}
        // 对创建通道交易进行验证
    	if chCrtEnv, err = sanityCheckAndSignConfigTx(chCrtEnv); err != nil {
    		return err
    	}
        // 创建广播客户端
    	var broadcastClient common.BroadcastClient
    	broadcastClient, err = cf.BroadcastFactory()
    	if err != nil {
    		return errors.WithMessage(err, "error getting broadcast client")
    	}
        // 将交易广播出去
    	defer broadcastClient.Close()
    	err = broadcastClient.Send(chCrtEnv)
    
    	return err
    }
    
    1. 定义了个Envelope结构体
    2. 判断channelTxFile文件(启动网络之前创建的channel.tx)是否存在,一般都是存在的。
    3. 如果存在的话从该文件中读取配置信息,不存在的话从默认的模板创建,最后返回Envelope
    4. 对Envelope文件进行验证
    5. 创建用于广播信息的客户端,将创建的Envelope文件广播出去.

    3.2 orderer处理交易

    本节会在交易流程及orderer源码详细介绍

    4. 附录

    channel.tx文件

    {
        "payload":{
            "data":{
                "config_update":{
                    "channel_id":"mychannel",
                    "read_set":{
                        "groups":{
                            "Application":{
                                "groups":{
                                    "Org1MSP":{
                                        "mod_policy":"",
                                        "version":"0"
                                    },
                                    "Org2MSP":{
                                        "mod_policy":"",
                                        "version":"0"
                                    }
                                },
                                "mod_policy":"",
                                "version":"0"
                            }
                        },
                        "mod_policy":"",
                        "values":{
                            "Consortium":{
                                "mod_policy":"",
                                "version":"0"
                            }
                        },
                        "version":"0"
                    },
                    "write_set":{
                        "groups":{
                            "Application":{
                                "groups":{
                                    "Org1MSP":{
                                        "mod_policy":"",
                                        "version":"0"
                                    },
                                    "Org2MSP":{
                                        "mod_policy":"",
                                        "version":"0"
                                    }
                                },
                                "mod_policy":"Admins",
                                "policies":{
                                    "Admins":{
                                        "mod_policy":"Admins",
                                        "policy":{
                                            "type":3,
                                            "value":{
                                                "rule":"MAJORITY",
                                                "sub_policy":"Admins"
                                            }
                                        },
                                        "version":"0"
                                    },
                                    "Readers":{
                                        "mod_policy":"Admins",
                                        "policy":{
                                            "type":3,
                                            "value":{
                                                "rule":"ANY",
                                                "sub_policy":"Readers"
                                            }
                                        },
                                        "version":"0"
                                    },
                                    "Writers":{
                                        "mod_policy":"Admins",
                                        "policy":{
                                            "type":3,
                                            "value":{
                                                "rule":"ANY",
                                                "sub_policy":"Writers"
                                            }
                                        },
                                        "version":"0"
                                    }
                                },
                                "values":{
                                    "Capabilities":{
                                        "mod_policy":"Admins",
                                        "value":{
                                            "capabilities":{
                                                "V1_2":{
    
                                                }
                                            }
                                        },
                                        "version":"0"
                                    }
                                },
                                "version":"1"
                            }
                        },
                        "mod_policy":"",
                        "values":{
                            "Consortium":{
                                "mod_policy":"",
                                "value":{
                                    "name":"SampleConsortium"
                                },
                                "version":"0"
                            }
                        },
                        "version":"0"
                    }
                }
            },
            "header":{
                "channel_header":{
                    "channel_id":"mychannel",
                    "epoch":"0",
                    "timestamp":"2019-11-26T02:46:37.000Z",
                    "tx_id":"",
                    "type":2,
                    "version":0
                }
            }
        }
    }
    
    如果你觉得写的不错,请移步www.itkezhan.top或者关注公众号IT程序员客栈
  • 相关阅读:
    CS224n, lec 10, NMT & Seq2Seq Attn
    CS231n笔记 Lecture 11, Detection and Segmentation
    CS231n笔记 Lecture 10, Recurrent Neural Networks
    CS231n笔记 Lecture 9, CNN Architectures
    CS231n笔记 Lecture 8, Deep Learning Software
    CS231n笔记 Lecture 7, Training Neural Networks, Part 2
    pytorch坑点排雷
    Sorry, Ubuntu 17.10 has experienced an internal error
    VSCode配置python插件
    tmux配置与使用
  • 原文地址:https://www.cnblogs.com/i-dandan/p/11941666.html
Copyright © 2011-2022 走看看