如果看完创建与加入通道的部分,这里基本上比他们要更简单。
前面重复的部分我们就不再赘述,直接来到orderer来处理配置更新的部分。
func (bh *Handler) ProcessMessage(msg *cb.Envelope, addr string) (resp *ab.BroadcastResponse) {
...
if !isConfig {
...
} else { // isConfig
config, configSeq, err := processor.ProcessConfigUpdateMsg(msg)
err = processor.Configure(config, configSeq)
}
return &ab.BroadcastResponse{Status: cb.Status_SUCCESS}
}
创建通道的部分,我们已经知道当没有通道的时候,processor是SystemChannel来处理,而这里是完全不同的情况,会用StandardChannel来托管
StandardChannel
ProcessConfigUpdateMsg
func (s *StandardChannel) ProcessConfigUpdateMsg(env *cb.Envelope) (config *cb.Envelope, configSeq uint64, err error) {
logger.Debugf("Processing config update message for channel %s", s.support.ChainID())
// Call Sequence first. If seq advances between proposal and acceptance, this is okay, and will cause reprocessing
// however, if Sequence is called last, then a success could be falsely attributed to a newer configSeq
seq := s.support.Sequence()
err = s.filters.Apply(env)
if err != nil {
return nil, 0, err
}
configEnvelope, err := s.support.ProposeConfigUpdate(env)
if err != nil {
return nil, 0, err
}
config, err = utils.CreateSignedEnvelope(cb.HeaderType_CONFIG, s.support.ChainID(), s.support.Signer(), configEnvelope, msgVersion, epoch)
if err != nil {
return nil, 0, err
}
err = s.filters.Apply(config)
if err != nil {
return nil, 0, err
}
return config, seq, nil
}
这里首先会筛选一遍,创建通道的时候我们知道SystemChannel的过滤器,这里我们来看下StandardChannel的过滤器。
func CreateStandardChannelFilters(filterSupport channelconfig.Resources) *RuleSet { ordererConfig, ok := filterSupport.OrdererConfig() if !ok { logger.Panicf("Missing orderer config") } return NewRuleSet([]Rule{ EmptyRejectRule, NewExpirationRejectRule(filterSupport), NewSizeFilter(ordererConfig), NewSigFilter(policies.ChannelWriters, filterSupport), }) }
- envelope的签名身份不能过期
- 消息大小不能超标
- 要满足/channel/writer的权限,也就是Any member,看你配置。
如果过滤器都没问题,接下来处理配置。里面主要是将变更的配置与现有通道配置进行合并,产出一份完整的通道配置。
之后组装HeaderType_CONFIG类型的SignedProposal
再次做一遍筛选
之后的流程就是发给orderer的共识服务里去流转,中间的流程跟通道创建类似,这里直接跳到最终接收HeaderType_CONFIG的地方。
WriteConfigBlock
func (bw *BlockWriter) WriteConfigBlock(block *cb.Block, encodedMetadataValue []byte) {
...
switch chdr.Type {
case int32(cb.HeaderType_ORDERER_TRANSACTION):
...
case int32(cb.HeaderType_CONFIG):
configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data)
err = bw.support.Validate(configEnvelope)
bundle, err := bw.support.CreateBundle(chdr.ChannelId, configEnvelope.Config)
bw.support.Update(bundle)
default:
logger.Panicf("Told to write a config block with unknown header type: %v", chdr.Type)
}
bw.WriteBlock(block, encodedMetadataValue)
}
- 这里又将configEnvelope转换成bundle。这个过程已经转两次了,实在是浪费。不管了,配置部分就是这样,我习惯了。
- 为了更新配置,当然了需要去更新通道绑定的bundle,这次毫无意外调用了bw.support.Update(bundle),这里就是最终的目的,通道配置更新。
小结
之后就是写入本地账本,然后同步给orderer,然后被leaderpeer拉取,然后再同步非peer成员,然后整个世界都同步配置了。而全部都是通过update bundle来实现配置更新。