文章目录
根据Fabric中典型的业务流程,简单地分析相关的代码,包括创建通道(channel)、加入通道(channel)、安装智能合约(chaincode)、认可智能合约(chaincode)定义、提交智能合约(chaincode)定义、调用智能合约(chaincode)。为避免篇幅过大,本文只摘取部分有助于讲解的代码,篇幅过长的代码不摘录了,可以根据路径直接查看源代码。
0. peer命令简析
fabric/cmd/peer/main.go
引入了下面两个库:
- spf13/cobra库:Golang最主流的命令行框架
- spf13/viper库:用于读取环境变量或yaml里的配置选项
mainCmd.AddCommand(version.Cmd())
mainCmd.AddCommand(node.Cmd())
mainCmd.AddCommand(chaincode.Cmd(nil, cryptoProvider))
mainCmd.AddCommand(channel.Cmd(nil))
mainCmd.AddCommand(lifecycle.Cmd(cryptoProvider))
可以看到支持version、node、chaincode、channel、lifecycle这些功能。
1. 创建channel
internal/peer/channel/create.go
func executeCreate(cf *ChannelCmdFactory) error {
err := sendCreateChainTransaction(cf)
if err != nil {
return err
}
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
}
把configtxgen(configtx.yaml)生成的channel.tx文件进行签名后发送到orderer的broadcast接口;然后从orderer获取创世区块,写入block文件。
orderer/common/broadcast/broadcast.go
orderer处理消息的函数为ProcessMessage:
func (bh *Handler) ProcessMessage(msg *cb.Envelope, addr string) (resp *ab.BroadcastResponse) {
tracker := &MetricsTracker{
ChannelID: "unknown",
TxType: "unknown",
Metrics: bh.Metrics,
}
defer func() {
// This looks a little unnecessary, but if done directly as
// a defer, resp gets the (always nil) current state of resp
// and not the return value
tracker.Record(resp)
}()
tracker.BeginValidate()
chdr, isConfig, processor, err := bh.SupportRegistrar.BroadcastChannelSupport(msg)
if chdr != nil {
tracker.ChannelID = chdr.ChannelId
tracker.TxType = cb.HeaderType(chdr.Type).String()
}
if err != nil {
logger.Warningf("[channel: %s] Could not get message processor for serving %s: %s", tracker.ChannelID, addr, err)
return &ab.BroadcastResponse{
Status: cb.Status_BAD_REQUEST, Info: err.Error()}
}
if !isConfig {
// ......
if err = processor.WaitReady(); err != nil {
logger.Warningf("[channel: %s] Rejecting broadcast of message from %s with SERVICE_UNAVAILABLE: rejected by Consenter: %s", chdr.ChannelId, addr, err)
return &ab.BroadcastResponse{
Status: cb.Status_SERVICE_UNAVAILABLE, Info: e