github.com/anjalikarhana/fabric@v2.1.1+incompatible/orderer/common/msgprocessor/systemchannel.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package msgprocessor 8 9 import ( 10 "fmt" 11 12 "github.com/golang/protobuf/proto" 13 cb "github.com/hyperledger/fabric-protos-go/common" 14 "github.com/hyperledger/fabric/bccsp" 15 "github.com/hyperledger/fabric/common/channelconfig" 16 "github.com/hyperledger/fabric/common/configtx" 17 "github.com/hyperledger/fabric/common/policies" 18 "github.com/hyperledger/fabric/internal/pkg/identity" 19 "github.com/hyperledger/fabric/orderer/common/localconfig" 20 "github.com/hyperledger/fabric/protoutil" 21 "github.com/pkg/errors" 22 ) 23 24 // ChannelConfigTemplator can be used to generate config templates. 25 type ChannelConfigTemplator interface { 26 // NewChannelConfig creates a new template configuration manager. 27 NewChannelConfig(env *cb.Envelope) (channelconfig.Resources, error) 28 } 29 30 // MetadataValidator can be used to validate updates to the consensus-specific metadata. 31 type MetadataValidator interface { 32 ValidateConsensusMetadata(oldMetadata, newMetadata []byte, newChannel bool) error 33 } 34 35 // SystemChannel implements the Processor interface for the system channel. 36 type SystemChannel struct { 37 *StandardChannel 38 templator ChannelConfigTemplator 39 } 40 41 // NewSystemChannel creates a new system channel message processor. 42 func NewSystemChannel(support StandardChannelSupport, templator ChannelConfigTemplator, filters *RuleSet, bccsp bccsp.BCCSP) *SystemChannel { 43 logger.Debugf("Creating system channel msg processor for channel %s", support.ChannelID()) 44 return &SystemChannel{ 45 StandardChannel: NewStandardChannel(support, filters, bccsp), 46 templator: templator, 47 } 48 } 49 50 // CreateSystemChannelFilters creates the set of filters for the ordering system chain. 51 // 52 // In maintenance mode, require the signature of /Channel/Orderer/Writers. This will filter out configuration 53 // changes that are not related to consensus-type migration (e.g on /Channel/Application). 54 func CreateSystemChannelFilters( 55 config localconfig.TopLevel, 56 chainCreator ChainCreator, 57 ledgerResources channelconfig.Resources, 58 validator MetadataValidator, 59 ) *RuleSet { 60 rules := []Rule{ 61 EmptyRejectRule, 62 NewSizeFilter(ledgerResources), 63 NewSigFilter(policies.ChannelWriters, policies.ChannelOrdererWriters, ledgerResources), 64 NewSystemChannelFilter(ledgerResources, chainCreator, validator), 65 } 66 if !config.General.Authentication.NoExpirationChecks { 67 expirationRule := NewExpirationRejectRule(ledgerResources) 68 // In case of DoS, expiration is inserted before SigFilter, so it is evaluated first 69 rules = append(rules[:2], append([]Rule{expirationRule}, rules[2:]...)...) 70 } 71 return NewRuleSet(rules) 72 } 73 74 // ProcessNormalMsg handles normal messages, rejecting them if they are not bound for the system channel ID 75 // with ErrChannelDoesNotExist. 76 func (s *SystemChannel) ProcessNormalMsg(msg *cb.Envelope) (configSeq uint64, err error) { 77 channelID, err := protoutil.ChannelID(msg) 78 if err != nil { 79 return 0, err 80 } 81 82 // For the StandardChannel message processing, we would not check the channel ID, 83 // because the message processor is looked up by channel ID. 84 // However, the system channel message processor is the catch all for messages 85 // which do not correspond to an extant channel, so we must check it here. 86 if channelID != s.support.ChannelID() { 87 return 0, ErrChannelDoesNotExist 88 } 89 90 return s.StandardChannel.ProcessNormalMsg(msg) 91 } 92 93 // ProcessConfigUpdateMsg handles messages of type CONFIG_UPDATE either for the system channel itself 94 // or, for channel creation. In the channel creation case, the CONFIG_UPDATE is wrapped into a resulting 95 // ORDERER_TRANSACTION, and in the standard CONFIG_UPDATE case, a resulting CONFIG message 96 func (s *SystemChannel) ProcessConfigUpdateMsg(envConfigUpdate *cb.Envelope) (config *cb.Envelope, configSeq uint64, err error) { 97 channelID, err := protoutil.ChannelID(envConfigUpdate) 98 if err != nil { 99 return nil, 0, err 100 } 101 102 logger.Debugf("Processing config update tx with system channel message processor for channel ID %s", channelID) 103 104 if channelID == s.support.ChannelID() { 105 return s.StandardChannel.ProcessConfigUpdateMsg(envConfigUpdate) 106 } 107 108 // XXX we should check that the signature on the outer envelope is at least valid for some MSP in the system channel 109 110 logger.Debugf("Processing channel create tx for channel %s on system channel %s", channelID, s.support.ChannelID()) 111 112 // If the channel ID does not match the system channel, then this must be a channel creation transaction 113 114 bundle, err := s.templator.NewChannelConfig(envConfigUpdate) 115 if err != nil { 116 return nil, 0, err 117 } 118 119 newChannelConfigEnv, err := bundle.ConfigtxValidator().ProposeConfigUpdate(envConfigUpdate) 120 if err != nil { 121 return nil, 0, errors.WithMessagef(err, "error validating channel creation transaction for new channel '%s', could not successfully apply update to template configuration", channelID) 122 } 123 124 newChannelEnvConfig, err := protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG, channelID, s.support.Signer(), newChannelConfigEnv, msgVersion, epoch) 125 if err != nil { 126 return nil, 0, err 127 } 128 129 wrappedOrdererTransaction, err := protoutil.CreateSignedEnvelope(cb.HeaderType_ORDERER_TRANSACTION, s.support.ChannelID(), s.support.Signer(), newChannelEnvConfig, msgVersion, epoch) 130 if err != nil { 131 return nil, 0, err 132 } 133 134 // We re-apply the filters here, especially for the size filter, to ensure that the transaction we 135 // just constructed is not too large for our consenter. It additionally reapplies the signature 136 // check, which although not strictly necessary, is a good sanity check, in case the orderer 137 // has not been configured with the right cert material. The additional overhead of the signature 138 // check is negligible, as this is the channel creation path and not the normal path. 139 err = s.StandardChannel.filters.Apply(wrappedOrdererTransaction) 140 if err != nil { 141 return nil, 0, err 142 } 143 144 return wrappedOrdererTransaction, s.support.Sequence(), nil 145 } 146 147 // ProcessConfigMsg takes envelope of following two types: 148 // - `HeaderType_CONFIG`: system channel itself is the target of config, we simply unpack `ConfigUpdate` 149 // envelope from `LastUpdate` field and call `ProcessConfigUpdateMsg` on the underlying standard channel 150 // - `HeaderType_ORDERER_TRANSACTION`: it's a channel creation message, we unpack `ConfigUpdate` envelope 151 // and run `ProcessConfigUpdateMsg` on it 152 func (s *SystemChannel) ProcessConfigMsg(env *cb.Envelope) (*cb.Envelope, uint64, error) { 153 payload, err := protoutil.UnmarshalPayload(env.Payload) 154 if err != nil { 155 return nil, 0, err 156 } 157 158 if payload.Header == nil { 159 return nil, 0, fmt.Errorf("Abort processing config msg because no head was set") 160 } 161 162 if payload.Header.ChannelHeader == nil { 163 return nil, 0, fmt.Errorf("Abort processing config msg because no channel header was set") 164 } 165 166 chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader) 167 if err != nil { 168 return nil, 0, fmt.Errorf("Abort processing config msg because channel header unmarshalling error: %s", err) 169 } 170 171 switch chdr.Type { 172 case int32(cb.HeaderType_CONFIG): 173 configEnvelope := &cb.ConfigEnvelope{} 174 if err = proto.Unmarshal(payload.Data, configEnvelope); err != nil { 175 return nil, 0, err 176 } 177 178 return s.StandardChannel.ProcessConfigUpdateMsg(configEnvelope.LastUpdate) 179 180 case int32(cb.HeaderType_ORDERER_TRANSACTION): 181 env, err := protoutil.UnmarshalEnvelope(payload.Data) 182 if err != nil { 183 return nil, 0, fmt.Errorf("Abort processing config msg because payload data unmarshalling error: %s", err) 184 } 185 186 configEnvelope := &cb.ConfigEnvelope{} 187 _, err = protoutil.UnmarshalEnvelopeOfType(env, cb.HeaderType_CONFIG, configEnvelope) 188 if err != nil { 189 return nil, 0, fmt.Errorf("Abort processing config msg because payload data unmarshalling error: %s", err) 190 } 191 192 return s.ProcessConfigUpdateMsg(configEnvelope.LastUpdate) 193 194 default: 195 return nil, 0, fmt.Errorf("Panic processing config msg due to unexpected envelope type %s", cb.HeaderType_name[chdr.Type]) 196 } 197 } 198 199 // DefaultTemplatorSupport is the subset of the channel config required by the DefaultTemplator. 200 type DefaultTemplatorSupport interface { 201 // ConsortiumsConfig returns the ordering system channel's Consortiums config. 202 ConsortiumsConfig() (channelconfig.Consortiums, bool) 203 204 // OrdererConfig returns the ordering configuration and whether the configuration exists 205 OrdererConfig() (channelconfig.Orderer, bool) 206 207 // ConfigtxValidator returns the configtx manager corresponding to the system channel's current config. 208 ConfigtxValidator() configtx.Validator 209 210 // Signer returns the local signer suitable for signing forwarded messages. 211 Signer() identity.SignerSerializer 212 } 213 214 // DefaultTemplator implements the ChannelConfigTemplator interface and is the one used in production deployments. 215 type DefaultTemplator struct { 216 support DefaultTemplatorSupport 217 bccsp bccsp.BCCSP 218 } 219 220 // NewDefaultTemplator returns an instance of the DefaultTemplator. 221 func NewDefaultTemplator(support DefaultTemplatorSupport, bccsp bccsp.BCCSP) *DefaultTemplator { 222 return &DefaultTemplator{ 223 support: support, 224 bccsp: bccsp, 225 } 226 } 227 228 // NewChannelConfig creates a new template channel configuration based on the current config in the ordering system channel. 229 func (dt *DefaultTemplator) NewChannelConfig(envConfigUpdate *cb.Envelope) (channelconfig.Resources, error) { 230 configUpdatePayload, err := protoutil.UnmarshalPayload(envConfigUpdate.Payload) 231 if err != nil { 232 return nil, fmt.Errorf("Failing initial channel config creation because of payload unmarshaling error: %s", err) 233 } 234 235 configUpdateEnv, err := configtx.UnmarshalConfigUpdateEnvelope(configUpdatePayload.Data) 236 if err != nil { 237 return nil, fmt.Errorf("Failing initial channel config creation because of config update envelope unmarshaling error: %s", err) 238 } 239 240 if configUpdatePayload.Header == nil { 241 return nil, fmt.Errorf("Failed initial channel config creation because config update header was missing") 242 } 243 244 channelHeader, err := protoutil.UnmarshalChannelHeader(configUpdatePayload.Header.ChannelHeader) 245 if err != nil { 246 return nil, fmt.Errorf("Failed initial channel config creation because channel header was malformed: %s", err) 247 } 248 249 configUpdate, err := configtx.UnmarshalConfigUpdate(configUpdateEnv.ConfigUpdate) 250 if err != nil { 251 return nil, fmt.Errorf("Failing initial channel config creation because of config update unmarshaling error: %s", err) 252 } 253 254 if configUpdate.ChannelId != channelHeader.ChannelId { 255 return nil, fmt.Errorf("Failing initial channel config creation: mismatched channel IDs: '%s' != '%s'", configUpdate.ChannelId, channelHeader.ChannelId) 256 } 257 258 if configUpdate.WriteSet == nil { 259 return nil, fmt.Errorf("Config update has an empty writeset") 260 } 261 262 if configUpdate.WriteSet.Groups == nil || configUpdate.WriteSet.Groups[channelconfig.ApplicationGroupKey] == nil { 263 return nil, fmt.Errorf("Config update has missing application group") 264 } 265 266 if uv := configUpdate.WriteSet.Groups[channelconfig.ApplicationGroupKey].Version; uv != 1 { 267 return nil, fmt.Errorf("Config update for channel creation does not set application group version to 1, was %d", uv) 268 } 269 270 consortiumConfigValue, ok := configUpdate.WriteSet.Values[channelconfig.ConsortiumKey] 271 if !ok { 272 return nil, fmt.Errorf("Consortium config value missing") 273 } 274 275 consortium := &cb.Consortium{} 276 err = proto.Unmarshal(consortiumConfigValue.Value, consortium) 277 if err != nil { 278 return nil, fmt.Errorf("Error reading unmarshaling consortium name: %s", err) 279 } 280 281 applicationGroup := protoutil.NewConfigGroup() 282 consortiumsConfig, ok := dt.support.ConsortiumsConfig() 283 if !ok { 284 return nil, fmt.Errorf("The ordering system channel does not appear to resources creating channels") 285 } 286 287 consortiumConf, ok := consortiumsConfig.Consortiums()[consortium.Name] 288 if !ok { 289 return nil, fmt.Errorf("Unknown consortium name: %s", consortium.Name) 290 } 291 292 policyKey := channelconfig.ChannelCreationPolicyKey 293 if oc, ok := dt.support.OrdererConfig(); ok && oc.Capabilities().UseChannelCreationPolicyAsAdmins() { 294 // To resources the channel creation process, we use a copy of the Consortium's ChannelCreationPolicy 295 // to govern modification of the application group. We do this by creating a new policy in the 296 // Application group (with a copy of the policy info from the consortium) and set the mod policy 297 // of the Application group to the name of this policy. Historically, the name chosen was 298 // "ChannelCreationPolicy". Because this name did not overlap with the default policy names, the 299 // creation tx simply encoded the Readers/Writers/Admins policies in the write set at Version 0. 300 // However, because there was no /Channel/Application/Admins policy in the template config, 301 // it made evaluating the /Channel/Admins policy impossible. When the UseChannelCreationPolicyAsAdmins 302 // capability is enabled, To allow the /Channel/Admins policy to evaluate normally, we now attempt 303 // to use the standard policy name "Admins" instead of "ChannelCreationPolicy", when the user is 304 // submitting a configtx generated by a newer version of configtxgen. We detect if an old 305 // configtxgen was used to generate the configtx if the /Channel/Application/Admins policy has a 306 //version set to 0. Otherwise, we use the newer behavior. 307 applicationPolicies := configUpdate.WriteSet.Groups[channelconfig.ApplicationGroupKey].Policies 308 if applicationPolicies != nil { 309 if policy, ok := applicationPolicies[channelconfig.AdminsPolicyKey]; !ok || policy.Version != uint64(0) { 310 policyKey = channelconfig.AdminsPolicyKey 311 } 312 } 313 } 314 applicationGroup.Policies[policyKey] = &cb.ConfigPolicy{ 315 Policy: consortiumConf.ChannelCreationPolicy(), 316 ModPolicy: policyKey, 317 } 318 applicationGroup.ModPolicy = policyKey 319 320 // Get the current system channel config 321 systemChannelGroup := dt.support.ConfigtxValidator().ConfigProto().ChannelGroup 322 323 // If the consortium group has no members, allow the source request to have no members. However, 324 // if the consortium group has any members, there must be at least one member in the source request 325 if len(systemChannelGroup.Groups[channelconfig.ConsortiumsGroupKey].Groups[consortium.Name].Groups) > 0 && 326 len(configUpdate.WriteSet.Groups[channelconfig.ApplicationGroupKey].Groups) == 0 { 327 return nil, fmt.Errorf("Proposed configuration has no application group members, but consortium contains members") 328 } 329 330 // If the consortium has no members, allow the source request to contain arbitrary members 331 // Otherwise, require that the supplied members are a subset of the consortium members 332 if len(systemChannelGroup.Groups[channelconfig.ConsortiumsGroupKey].Groups[consortium.Name].Groups) > 0 { 333 for orgName := range configUpdate.WriteSet.Groups[channelconfig.ApplicationGroupKey].Groups { 334 consortiumGroup, ok := systemChannelGroup.Groups[channelconfig.ConsortiumsGroupKey].Groups[consortium.Name].Groups[orgName] 335 if !ok { 336 return nil, fmt.Errorf("Attempted to include a member which is not in the consortium") 337 } 338 applicationGroup.Groups[orgName] = proto.Clone(consortiumGroup).(*cb.ConfigGroup) 339 } 340 } 341 342 channelGroup := protoutil.NewConfigGroup() 343 344 // Copy the system channel Channel level config to the new config 345 for key, value := range systemChannelGroup.Values { 346 channelGroup.Values[key] = proto.Clone(value).(*cb.ConfigValue) 347 if key == channelconfig.ConsortiumKey { 348 // Do not set the consortium name, we do this later 349 continue 350 } 351 } 352 353 for key, policy := range systemChannelGroup.Policies { 354 channelGroup.Policies[key] = proto.Clone(policy).(*cb.ConfigPolicy) 355 } 356 357 // Set the new config orderer group to the system channel orderer group and the application group to the new application group 358 channelGroup.Groups[channelconfig.OrdererGroupKey] = proto.Clone(systemChannelGroup.Groups[channelconfig.OrdererGroupKey]).(*cb.ConfigGroup) 359 channelGroup.Groups[channelconfig.ApplicationGroupKey] = applicationGroup 360 channelGroup.Values[channelconfig.ConsortiumKey] = &cb.ConfigValue{ 361 Value: protoutil.MarshalOrPanic(channelconfig.ConsortiumValue(consortium.Name).Value()), 362 ModPolicy: channelconfig.AdminsPolicyKey, 363 } 364 365 // Non-backwards compatible bugfix introduced in v1.1 366 // The capability check should be removed once v1.0 is deprecated 367 if oc, ok := dt.support.OrdererConfig(); ok && oc.Capabilities().PredictableChannelTemplate() { 368 channelGroup.ModPolicy = systemChannelGroup.ModPolicy 369 zeroVersions(channelGroup) 370 } 371 372 bundle, err := channelconfig.NewBundle(channelHeader.ChannelId, &cb.Config{ 373 ChannelGroup: channelGroup, 374 }, dt.bccsp) 375 376 if err != nil { 377 return nil, err 378 } 379 380 return bundle, nil 381 } 382 383 // zeroVersions recursively iterates over a config tree, setting all versions to zero 384 func zeroVersions(cg *cb.ConfigGroup) { 385 cg.Version = 0 386 387 for _, value := range cg.Values { 388 value.Version = 0 389 } 390 391 for _, policy := range cg.Policies { 392 policy.Version = 0 393 } 394 395 for _, group := range cg.Groups { 396 zeroVersions(group) 397 } 398 }