Hyperledger Fabric 源码 浅谈

  • 2021-09-18 更: 现在请忽略这篇博文吧,后续再补,fabric的每一块,基本都很清楚了
  • 2020-12-21
  • fabric-sdk-java,fabric-ca 都改完了,fabric改的差不多了,源码有空再补吧,现在留着的挺浅的:-)
  • 2020-07-22
    • 添加创建channel时候的相关debug

DEBUG源码流程所需:

进入 github.com/hyperledger/fabric/cmd/orderer
赋值orderer.yaml 到该目录
在orderer.yaml 中配置tls 相关信息,
再在主函数中设置
os.Setenv("FABRIC_CFG_PATH", "/Users/joker/go/src/github.com/hyperledger/fabric/cmd/orderer")
os.Setenv("FABRIC_LOGGING_SPEC", "DEBUG")
即可

Orderer

创建channel:

  • 路口处理方法为:
    // Handle reads requests from a Broadcast stream, processes them, and returns the responses to the stream
    func (bh *Handler) Handle(srv ab.AtomicBroadcast_BroadcastServer) error {
    	addr := util.ExtractRemoteAddress(srv.Context()) // 解析获取广播的ip地址
    	logger.Debugf("Starting new broadcast loop for %s", addr)
    	for {
    		msg, err := srv.Recv() // 接收节点发送过来的数据,cli 或者是peer
    		if err == io.EOF {
    			logger.Debugf("Received EOF from %s, hangup", addr)
    			return nil
    		}
    		if err != nil {
    			logger.Warningf("Error reading from %s: %s", addr, err)
    			return err
    		}
    		// 开始处理消息
    		resp := bh.ProcessMessage(msg, addr)
    		// 响应消息的结果
    		err = srv.Send(resp)
    		if resp.Status != cb.Status_SUCCESS {
    			return err
    		}
    
    		if err != nil {
    			logger.Warningf("Error sending to %s: %s", addr, err)
    			return err
    		}
    	}
    
    }
    
    • srv.Recv():广播并且接收节点发送过来的消息

    • func (ss *serverStream) RecvMsg(msg interface{}) error {
      err := ss.ServerStream.RecvMsg(msg)
      // 同时会有校验,校验的只是日志相关,因此不去细究
      if ce := ss.payloadLogger.Check(ss.payloadLevel, “received stream message”); ce != nil { //
      ce.Write(ProtoMessage(“message”, msg))
      }
      return err
      }

    • *处理消息:resp := bh.ProcessMessage(msg, addr)

      • 内部代码细究

        • 打点日志跟踪相关
      • 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()

        }

        • **Handler 调用 ChannelSupportRegistrar **,

        • 内部调用如下:

        • 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()}
            	}
          
        • ChannelSupportRegistarar的声明:

        • // ChannelSupportRegistrar provides a way for the Handler to look up the Support for a channel
          type ChannelSupportRegistrar interface {
          // BroadcastChannelSupport returns the message channel header, whether the message is a config update
          // and the channel resources for a message or an error if the message is not a message which can
          // be processed directly (like CONFIG and ORDERER_TRANSACTION messages)
          BroadcastChannelSupport(msg *cb.Envelope) (*cb.ChannelHeader, bool, ChannelSupport, error)
          }

          如注释所言,提供的是对于channel 的适配性

        • 实际调用:

        • func (r *Registrar) BroadcastChannelSupport(msg *cb.Envelope) (*cb.ChannelHeader, bool, *ChainSupport, error) {
          	// 先解析 envelop 对象,并且简单校验
          	chdr, err := protoutil.ChannelHeader(msg)
          	if err != nil {
          		return nil, false, nil, fmt.Errorf("could not determine channel ID: %s", err)
          	}
           // registrar 对象内部有一个 	chains map[string]*ChainSupport的成员
           // 变量, 通过读写锁控制,因为刚开始创建channel,所以内部只有一个系统channel
           // Q : 什么时候写入: 
           // 	A: 
          	cs := r.GetChain(chdr.ChannelId)
          	// New channel creation
          	if cs == nil {
          	// 该channel(demochannel)不存在 ,则获取到系统channel
          		sysChan := r.SystemChannel()
          		if sysChan == nil {
          			return nil, false, nil, errors.New("channel creation request not allowed because the orderer system channel is not defined")
          		}
          		// 则用 系统channel 代替 currenChanel
          		cs = sysChan
          	}
          
          	isConfig := false
           // ClassifyMsg 是Processor 接口中的方法,该接口的存在类似于责任链
          	switch cs.ClassifyMsg(chdr) { // 通过envelop中的消息判断消息类型,有 配置更新msg 也有配置msg
          	case msgprocessor.ConfigUpdateMsg:
          	// 初次创建,需要更新配置,所以是 CONFIG_UPDATE 消息类型
          		isConfig = true
          	case msgprocessor.ConfigMsg:
          		return chdr, false, nil, errors.New("message is of type that cannot be processed directly")
          	default:
          	}
          
          	return chdr, isConfig, cs, nil
          }
          
        • 之后则判断是配置更新消息,还是普通的消息:

        • 配置更新消息:

        • else { // isConfig
          		logger.Debugf("[channel: %s] Broadcast is processing config update message from %s", chdr.ChannelId, addr)
          		 // 调用Processor 接口体系 ,处理 配置更新消息
          		config, configSeq, err := processor.ProcessConfigUpdateMsg(msg)
          		if err != nil {
          			logger.Warningf("[channel: %s] Rejecting broadcast of config message from %s because of error: %s", chdr.ChannelId, addr, err)
          			return &ab.BroadcastResponse{Status: ClassifyError(err), Info: err.Error()}
          		}
          		tracker.EndValidate()
          
          		tracker.BeginEnqueue()
          		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: err.Error()}
          		}
          
          		err = processor.Configure(config, configSeq)
          		if err != nil {
          			logger.Warningf("[channel: %s] Rejecting broadcast of config message from %s with SERVICE_UNAVAILABLE: rejected by Configure: %s", chdr.ChannelId, addr, err)
          			return &ab.BroadcastResponse{Status: cb.Status_SERVICE_UNAVAILABLE, Info: err.Error()}
          		}
          	}
          
        • Processor#ProcessConfigUpdateMsg这个方法只用于配置更新CONFIG_UPDATE 或者是系统channel自身,实际调用如下:

        • func (s *SystemChannel) ProcessConfigUpdateMsg(envConfigUpdate *cb.Envelope) (config *cb.Envelope, configSeq uint64, err error) {
          	// 解析获取消息中的channelId
          	channelID, err := protoutil.ChannelID(envConfigUpdate)
          	// fabric 安全性的体现之一,名称是否要对应,内部调用的是
          	if channelID == s.support.ChannelID() {
          		return s.StandardChannel.ProcessConfigUpdateMsg(envConfigUpdate)
          	}
          
          	// 没进入上路的方法,就说明不是系统通道,那就是创建被,创建则意味着需要配置更新
          	// 内部方法与 configtx.yaml有关,
          	bundle, err := s.templator.NewChannelConfig(envConfigUpdate)
          	if err != nil {
          		return nil, 0, err
          	}
          
        • NewChannelConfig方法 如下,常见的问题都是出自这里:,什么version不对,policy错误等信息

          if configUpdate.WriteSet.Groups == nil || configUpdate.WriteSet.Groups[channelconfig.ApplicationGroupKey] == nil {
          		return nil, fmt.Errorf("Config update has missing application group")
          	}
          
          	if uv := configUpdate.WriteSet.Groups[channelconfig.ApplicationGroupKey].Version; uv != 1 {
          		return nil, fmt.Errorf("Config update for channel creation does not set application group version to 1, was %d", uv)
          	}
            // 对应configtxgen的consortium ,
          	consortiumConfigValue, ok := configUpdate.WriteSet.Values[channelconfig.ConsortiumKey]
          	.......
          	.......
          	.......
          	接下来就是一系列的初始化赋值操作
          .........
          .........
          .........
          	if oc, ok := dt.support.OrdererConfig(); ok && oc.Capabilities().PredictableChannelTemplate() {
          		channelGroup.ModPolicy = systemChannelGroup.ModPolicy
          		// 全部初始化版本号为0,在区块链中版本号,以及处理好都非常重要
          		zeroVersions(channelGroup)
          	}
          // 生成新的配置,内部有一块方法要注意:
          	bundle, err := channelconfig.NewBundle(channelHeader.ChannelId, &cb.Config{
          		ChannelGroup: channelGroup,
          	}, dt.bccsp)
          
          	if err != nil {
          		return nil, err
          	}
          
          	return bundle, nil
          
        • NewBundle

        • .....
          .....
          .....
          policyProviderMap := make(map[int32]policies.Provider)
          	for pType := range cb.Policy_PolicyType_name {
          		rtype := cb.Policy_PolicyType(pType)
          		switch rtype {
          		case cb.Policy_UNKNOWN:
          			// Do not register a handler
          		case cb.Policy_SIGNATURE:
          			policyProviderMap[pType] = cauthdsl.NewPolicyProvider(channelConfig.MSPManager())
          		case cb.Policy_MSP:
          			// Add hook for MSP Handler here
          		}
          	}
          map信息为:
          var Policy_PolicyType_name = map[int32]string{
          	0: "UNKNOWN",
          	1: "SIGNATURE",
          	2: "MSP",
          	3: "IMPLICIT_META",
          }
          
        • 之后则初始化manager信息,如

          • role信息

          • policy信息:

            • sign nOutOf 还是 SignBy
            • Admins,readers,writers等
          • policyManager, err := policies.NewManagerImpl(RootGroupKey, policyProviderMap, config.ChannelGroup)
            	if err != nil {
            		return nil, errors.Wrap(err, "initializing policymanager failed")
            	}
            
            
          • 再配置校验相关:

            • configtxManager, err := configtx.NewValidatorImpl(channelID, config, RootGroupKey, policyManager)
              	if err != nil {
              		return nil, errors.Wrap(err, "initializing configtx manager failed")
              	}
              
        • 接着就开始真正的处理消息了

        • 通过刚才生成的bundle
            	newChannelConfigEnv, err := bundle.ConfigtxValidator().ProposeConfigUpdate(envConfigUpdate)
            	if err != nil {
            		return nil, 0, errors.WithMessagef(err, "error validating channel creation transaction for new channel '%s', could not successfully apply update to template configuration", channelID)
            	}
          
        • ,交给内部的成员变量实现 ValidatorImpl

        • func (vi *ValidatorImpl) proposeConfigUpdate(configtx *cb.Envelope) (*cb.ConfigEnvelope, error) {
          // proto 反序列化
          	configUpdateEnv, err := protoutil.EnvelopeToConfigUpdate(configtx)
          	if err != nil {
          		return nil, errors.Errorf("error converting envelope to config update: %s", err)
          	}
           // 校验消费是否合理,大多数错误也是在这里爆出
          	configMap, err := vi.authorizeUpdate(configUpdateEnv)
          	if err != nil {
          		return nil, errors.Errorf("error authorizing update: %s", err)
          	}
          
        • vi.authorizeUpdate 会校验如下

          • 注意,每次发生更新都会使得版本号+1,所以会总是提示版本号不一致的问题

          • channelId是否一致

          • 读写集

          • func (vi *ValidatorImpl) authorizeUpdate(configUpdateEnv *cb.ConfigUpdateEnvelope) (map[string]comparable, error) {
            	if configUpdateEnv == nil {
            		return nil, errors.Errorf("cannot process nil ConfigUpdateEnvelope")
            	}
            
            	configUpdate, err := UnmarshalConfigUpdate(configUpdateEnv.ConfigUpdate)
            	if err != nil {
            		return nil, err
            	}
            
            	if configUpdate.ChannelId != vi.channelID {
            		return nil, errors.Errorf("ConfigUpdate for channel '%s' but envelope for channel '%s'", configUpdate.ChannelId, vi.channelID)
            	}
            
            	readSet, err := mapConfig(configUpdate.ReadSet, vi.namespace)
            	if err != nil {
            		return nil, errors.Wrapf(err, "error mapping ReadSet")
            	}
            	// 校验读
            	err = vi.verifyReadSet(readSet)
            	if err != nil {
            		return nil, errors.Wrapf(err, "error validating ReadSet")
            	}
             // 校验写
            	writeSet, err := mapConfig(configUpdate.WriteSet, vi.namespace)
            	if err != nil {
            		return nil, errors.Wrapf(err, "error mapping WriteSet")
            	}
            	
            	// 计算获取?
            	deltaSet := computeDeltaSet(readSet, writeSet)
            	signedData, err := protoutil.ConfigUpdateEnvelopeAsSignedData(configUpdateEnv)
            	if err != nil {
            		return nil, err
            	}
            
            // 通过上述集合校验签名数据 ,内部会调用 validateModPolicy,通过signedData
            // 获取到modPolicy ,判断是admin用户还是普通用户
            // 判断是否有/Channel/Application/ChannelCreationPolicy 这个policy
            	if err = vi.verifyDeltaSet(deltaSet, signedData); err != nil {
            		return nil, errors.Wrapf(err, "error validating DeltaSet")
            	}
            
            	fullProposedConfig := vi.computeUpdateResult(deltaSet)
            	if err := verifyFullProposedConfig(writeSet, fullProposedConfig); err != nil {
            		return nil, errors.Wrapf(err, "full config did not verify")
            	}
            
            	return fullProposedConfig, nil
            }
            
          • 上述校验通过之后,需要将map转为Config实体

            • channelGroup, err := configMapToConfig(configMap, vi.namespace)
              	if err != nil {
              		return nil, errors.Errorf("could not turn configMap back to channelGroup: %s", err)
              	}
              
          • 最后返回结果:,同时 sequence 会+1

            • return &cb.ConfigEnvelope{
              		Config: &cb.Config{
              			Sequence:     vi.sequence + 1,
              			ChannelGroup: channelGroup,
              		},
              		LastUpdate: configtx,
              	}, nil
              
          • 成功之后,则需要重新生成签名数据,返回给客户端

            	newChannelEnvConfig, err := protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG, channelID, s.support.Signer(), newChannelConfigEnv, msgVersion, epoch)
            	if err != nil {
            		return nil, 0, err
            	}
            
            	wrappedOrdererTransaction, err := protoutil.CreateSignedEnvelope(cb.HeaderType_ORDERER_TRANSACTION, s.support.ChannelID(), s.support.Signer(), newChannelEnvConfig, msgVersion, epoch)
            	if err != nil {
            		return nil, 0, err
            	}
            
          • 最后一步,准备好数据之后,不能将任意的数据回送回去,还需要进行过滤,防止恶意或者无效的包,client无法兼容:,内部是 Rule 接口

          • err = s.StandardChannel.filters.Apply(wrappedOrdererTransaction)
              	if err != nil {
              		return nil, 0, err
              	}
              
              	return wrappedOrdererTransaction, s.support.Sequence(), nil
            }
            
            • Rule接口定义如下

            • accept请求或者直接reject请求

              // Rule defines a filter function which accepts, rejects, or forwards (to the next rule) an Envelope
              type Rule interface {
              // Apply applies the rule to the given Envelope, either successfully or returns error
              Apply(message *ab.Envelope) error
              }

            • 默认装配有如下 filter:

              • MaxBytes: 防止transaction 过大
              • expiration 防止请求超时
              • SigFilter: 校验policy是否合法
              • systemChainFilter: systemChain添加相关信息
          • 当更新完消息所带来的配置变化之后,处理业务

          • tracker.BeginEnqueue()
              		// 默认是调用 一个空的实现
              		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: err.Error()}
              		}
              		// 之后则是开始调用Confiure ,该方法的作用在于  ? 
              		err = processor.Configure(config, configSeq)
              		if err != nil {
              			logger.Warningf("[channel: %s] Rejecting broadcast of config message from %s with SERVICE_UNAVAILABLE: rejected by Configure: %s", chdr.ChannelId, addr, err)
              			return &ab.BroadcastResponse{Status: cb.Status_SERVICE_UNAVAILABLE, Info: err.Error()}
              		}
              
            
  • 处理完消息之后,发送返回值

    • 通过grpc

    • err = srv.Send(resp)
        		if resp.Status != cb.Status_SUCCESS {
        			return err
        		}
        
        		if err != nil {
        			logger.Warningf("Error sending to %s: %s", addr, err)
        			return err
        		}
      
  • envelop 校验阶段

    • Processor(msg处理器) -> Rule(msg)->Support(msp)
      • Rule:校验 是直接reject 还是 filter
        • SigFIlter:

      • StandardChannelSupport
        • 校验
  • envelop校验结束

实例化channel


疑问

  • Q: Registrar 中存储的channel信息,什么时候 增加,删除,修改?
    • A:

一些临时的东西

消息通讯

  • 消息通过 Processor这个接口处理

    • // Processor provides the methods necessary to classify and process any message which
      // arrives through the Broadcast interface.
      type Processor interface {
      	// 用于 检测 msg 的头部header信息,判断用哪个 消息处理器来处理消息 ,类似于责任链模式
      	ClassifyMsg(chdr *cb.ChannelHeader) Classification
      
      	
      	// 处理消息的同时返回消息的序列号,用来校验消息是否过期
      	ProcessNormalMsg(env *cb.Envelope) (configSeq uint64, err error)
      
      	// ProcessConfigUpdateMsg will attempt to apply the config update to the current configuration, and if successful
      	// return the resulting config message and the configSeq the config was computed from.  If the config update message
      	// is invalid, an error is returned.
      	// 处理配置更新信息,每个processor 自身都有一大堆配置,同样也会返回序列号,和新的配置信息
      	ProcessConfigUpdateMsg(env *cb.Envelope) (config *cb.Envelope, configSeq uint64, err error)
      
      	// ProcessConfigMsg takes message of type `ORDERER_TX` or `CONFIG`, unpack the ConfigUpdate envelope embedded
      	// in it, and call `ProcessConfigUpdateMsg` to produce new Config message of the same type as original message.
      	// This method is used to re-validate and reproduce config message, if it's deemed not to be valid anymore.
      	// 可以认为只是一个包装方法
      	ProcessConfigMsg(env *cb.Envelope) (*cb.Envelope, uint64, error)
      }
      
      
    • 关键的实现类:

      • SigFilter

        • // SigFilter stores the name of the policy to apply to deliver requests to
          // determine whether a client is authorized
          type SigFilter struct {
          	normalPolicyName      string
          	maintenancePolicyName string
          	support               SigFilterSupport
          }
          
        • 判断是否合法

          • 如判断 /Channel/Orderer/Writers. 或者
  • orderer 通过 Rule接口决定是否过滤这个msg 还是直接reject这个消息

    • // Rule defines a filter function which accepts, rejects, or forwards (to the next rule) an Envelope
      type Rule interface {
      	// Apply applies the rule to the given Envelope, either successfully or returns error
      	Apply(message *ab.Envelope) error
      }
      
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值