- 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 校验阶段
-
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 }
-