github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/orderer/common/multichannel/manager.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 // Package multichannel tracks the channel resources for the orderer. It initially 8 // loads the set of existing channels, and provides an interface for users of these 9 // channels to retrieve them, or create new ones. 10 package multichannel 11 12 import ( 13 "fmt" 14 15 "github.com/hyperledger/fabric/common/config" 16 "github.com/hyperledger/fabric/common/configtx" 17 configtxapi "github.com/hyperledger/fabric/common/configtx/api" 18 "github.com/hyperledger/fabric/common/policies" 19 "github.com/hyperledger/fabric/orderer/common/ledger" 20 cb "github.com/hyperledger/fabric/protos/common" 21 "github.com/hyperledger/fabric/protos/utils" 22 "github.com/op/go-logging" 23 24 "github.com/golang/protobuf/proto" 25 "github.com/hyperledger/fabric/common/crypto" 26 ) 27 28 var logger = logging.MustGetLogger("orderer/multichannel") 29 30 const ( 31 msgVersion = int32(0) 32 epoch = 0 33 ) 34 35 // Manager coordinates the creation and access of chains 36 type Manager interface { 37 // GetChain retrieves the chain support for a chain (and whether it exists) 38 GetChain(chainID string) (ChainSupport, bool) 39 40 // SystemChannelID returns the channel ID for the system channel 41 SystemChannelID() string 42 43 // NewChannelConfig returns a bare bones configuration ready for channel 44 // creation request to be applied on top of it 45 NewChannelConfig(envConfigUpdate *cb.Envelope) (configtxapi.Manager, error) 46 } 47 48 type configResources struct { 49 configtxapi.Manager 50 } 51 52 func (cr *configResources) SharedConfig() config.Orderer { 53 oc, ok := cr.OrdererConfig() 54 if !ok { 55 logger.Panicf("[channel %s] has no orderer configuration", cr.ChainID()) 56 } 57 return oc 58 } 59 60 type ledgerResources struct { 61 *configResources 62 ledger ledger.ReadWriter 63 } 64 65 type multiLedger struct { 66 chains map[string]*chainSupport 67 consenters map[string]Consenter 68 ledgerFactory ledger.Factory 69 signer crypto.LocalSigner 70 systemChannelID string 71 systemChannel *chainSupport 72 } 73 74 func getConfigTx(reader ledger.Reader) *cb.Envelope { 75 lastBlock := ledger.GetBlock(reader, reader.Height()-1) 76 index, err := utils.GetLastConfigIndexFromBlock(lastBlock) 77 if err != nil { 78 logger.Panicf("Chain did not have appropriately encoded last config in its latest block: %s", err) 79 } 80 configBlock := ledger.GetBlock(reader, index) 81 if configBlock == nil { 82 logger.Panicf("Config block does not exist") 83 } 84 85 return utils.ExtractEnvelopeOrPanic(configBlock, 0) 86 } 87 88 // NewManagerImpl produces an instance of a Manager 89 func NewManagerImpl(ledgerFactory ledger.Factory, consenters map[string]Consenter, signer crypto.LocalSigner) Manager { 90 ml := &multiLedger{ 91 chains: make(map[string]*chainSupport), 92 ledgerFactory: ledgerFactory, 93 consenters: consenters, 94 signer: signer, 95 } 96 97 existingChains := ledgerFactory.ChainIDs() 98 for _, chainID := range existingChains { 99 rl, err := ledgerFactory.GetOrCreate(chainID) 100 if err != nil { 101 logger.Panicf("Ledger factory reported chainID %s but could not retrieve it: %s", chainID, err) 102 } 103 configTx := getConfigTx(rl) 104 if configTx == nil { 105 logger.Panic("Programming error, configTx should never be nil here") 106 } 107 ledgerResources := ml.newLedgerResources(configTx) 108 chainID := ledgerResources.ChainID() 109 110 if _, ok := ledgerResources.ConsortiumsConfig(); ok { 111 if ml.systemChannelID != "" { 112 logger.Panicf("There appear to be two system chains %s and %s", ml.systemChannelID, chainID) 113 } 114 chain := newChainSupport(createSystemChainFilters(ml, ledgerResources), 115 ledgerResources, 116 consenters, 117 signer) 118 logger.Infof("Starting with system channel %s and orderer type %s", chainID, chain.SharedConfig().ConsensusType()) 119 ml.chains[chainID] = chain 120 ml.systemChannelID = chainID 121 ml.systemChannel = chain 122 // We delay starting this chain, as it might try to copy and replace the chains map via newChain before the map is fully built 123 defer chain.start() 124 } else { 125 logger.Debugf("Starting chain: %s", chainID) 126 chain := newChainSupport(createStandardFilters(ledgerResources), 127 ledgerResources, 128 consenters, 129 signer) 130 ml.chains[chainID] = chain 131 chain.start() 132 } 133 134 } 135 136 if ml.systemChannelID == "" { 137 logger.Panicf("No system chain found. If bootstrapping, does your system channel contain a consortiums group definition?") 138 } 139 140 return ml 141 } 142 143 func (ml *multiLedger) SystemChannelID() string { 144 return ml.systemChannelID 145 } 146 147 // GetChain retrieves the chain support for a chain (and whether it exists) 148 func (ml *multiLedger) GetChain(chainID string) (ChainSupport, bool) { 149 cs, ok := ml.chains[chainID] 150 return cs, ok 151 } 152 153 func (ml *multiLedger) newLedgerResources(configTx *cb.Envelope) *ledgerResources { 154 initializer := configtx.NewInitializer() 155 configManager, err := configtx.NewManagerImpl(configTx, initializer, nil) 156 if err != nil { 157 logger.Panicf("Error creating configtx manager and handlers: %s", err) 158 } 159 160 chainID := configManager.ChainID() 161 162 ledger, err := ml.ledgerFactory.GetOrCreate(chainID) 163 if err != nil { 164 logger.Panicf("Error getting ledger for %s", chainID) 165 } 166 167 return &ledgerResources{ 168 configResources: &configResources{Manager: configManager}, 169 ledger: ledger, 170 } 171 } 172 173 func (ml *multiLedger) newChain(configtx *cb.Envelope) { 174 ledgerResources := ml.newLedgerResources(configtx) 175 ledgerResources.ledger.Append(ledger.CreateNextBlock(ledgerResources.ledger, []*cb.Envelope{configtx})) 176 177 // Copy the map to allow concurrent reads from broadcast/deliver while the new chainSupport is 178 newChains := make(map[string]*chainSupport) 179 for key, value := range ml.chains { 180 newChains[key] = value 181 } 182 183 cs := newChainSupport(createStandardFilters(ledgerResources), ledgerResources, ml.consenters, ml.signer) 184 chainID := ledgerResources.ChainID() 185 186 logger.Infof("Created and starting new chain %s", chainID) 187 188 newChains[string(chainID)] = cs 189 cs.start() 190 191 ml.chains = newChains 192 } 193 194 func (ml *multiLedger) channelsCount() int { 195 return len(ml.chains) 196 } 197 198 func (ml *multiLedger) NewChannelConfig(envConfigUpdate *cb.Envelope) (configtxapi.Manager, error) { 199 configUpdatePayload, err := utils.UnmarshalPayload(envConfigUpdate.Payload) 200 if err != nil { 201 return nil, fmt.Errorf("Failing initial channel config creation because of payload unmarshaling error: %s", err) 202 } 203 204 configUpdateEnv, err := configtx.UnmarshalConfigUpdateEnvelope(configUpdatePayload.Data) 205 if err != nil { 206 return nil, fmt.Errorf("Failing initial channel config creation because of config update envelope unmarshaling error: %s", err) 207 } 208 209 if configUpdatePayload.Header == nil { 210 return nil, fmt.Errorf("Failed initial channel config creation because config update header was missing") 211 } 212 channelHeader, err := utils.UnmarshalChannelHeader(configUpdatePayload.Header.ChannelHeader) 213 214 configUpdate, err := configtx.UnmarshalConfigUpdate(configUpdateEnv.ConfigUpdate) 215 if err != nil { 216 return nil, fmt.Errorf("Failing initial channel config creation because of config update unmarshaling error: %s", err) 217 } 218 219 if configUpdate.ChannelId != channelHeader.ChannelId { 220 return nil, fmt.Errorf("Failing initial channel config creation: mismatched channel IDs: '%s' != '%s'", configUpdate.ChannelId, channelHeader.ChannelId) 221 } 222 223 if configUpdate.WriteSet == nil { 224 return nil, fmt.Errorf("Config update has an empty writeset") 225 } 226 227 if configUpdate.WriteSet.Groups == nil || configUpdate.WriteSet.Groups[config.ApplicationGroupKey] == nil { 228 return nil, fmt.Errorf("Config update has missing application group") 229 } 230 231 if uv := configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Version; uv != 1 { 232 return nil, fmt.Errorf("Config update for channel creation does not set application group version to 1, was %d", uv) 233 } 234 235 consortiumConfigValue, ok := configUpdate.WriteSet.Values[config.ConsortiumKey] 236 if !ok { 237 return nil, fmt.Errorf("Consortium config value missing") 238 } 239 240 consortium := &cb.Consortium{} 241 err = proto.Unmarshal(consortiumConfigValue.Value, consortium) 242 if err != nil { 243 return nil, fmt.Errorf("Error reading unmarshaling consortium name: %s", err) 244 } 245 246 applicationGroup := cb.NewConfigGroup() 247 consortiumsConfig, ok := ml.systemChannel.ConsortiumsConfig() 248 if !ok { 249 return nil, fmt.Errorf("The ordering system channel does not appear to support creating channels") 250 } 251 252 consortiumConf, ok := consortiumsConfig.Consortiums()[consortium.Name] 253 if !ok { 254 return nil, fmt.Errorf("Unknown consortium name: %s", consortium.Name) 255 } 256 257 applicationGroup.Policies[config.ChannelCreationPolicyKey] = &cb.ConfigPolicy{ 258 Policy: consortiumConf.ChannelCreationPolicy(), 259 } 260 applicationGroup.ModPolicy = config.ChannelCreationPolicyKey 261 262 // Get the current system channel config 263 systemChannelGroup := ml.systemChannel.ConfigEnvelope().Config.ChannelGroup 264 265 // If the consortium group has no members, allow the source request to have no members. However, 266 // if the consortium group has any members, there must be at least one member in the source request 267 if len(systemChannelGroup.Groups[config.ConsortiumsGroupKey].Groups[consortium.Name].Groups) > 0 && 268 len(configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups) == 0 { 269 return nil, fmt.Errorf("Proposed configuration has no application group members, but consortium contains members") 270 } 271 272 // If the consortium has no members, allow the source request to contain arbitrary members 273 // Otherwise, require that the supplied members are a subset of the consortium members 274 if len(systemChannelGroup.Groups[config.ConsortiumsGroupKey].Groups[consortium.Name].Groups) > 0 { 275 for orgName := range configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups { 276 consortiumGroup, ok := systemChannelGroup.Groups[config.ConsortiumsGroupKey].Groups[consortium.Name].Groups[orgName] 277 if !ok { 278 return nil, fmt.Errorf("Attempted to include a member which is not in the consortium") 279 } 280 applicationGroup.Groups[orgName] = consortiumGroup 281 } 282 } 283 284 channelGroup := cb.NewConfigGroup() 285 286 // Copy the system channel Channel level config to the new config 287 for key, value := range systemChannelGroup.Values { 288 channelGroup.Values[key] = value 289 if key == config.ConsortiumKey { 290 // Do not set the consortium name, we do this later 291 continue 292 } 293 } 294 295 for key, policy := range systemChannelGroup.Policies { 296 channelGroup.Policies[key] = policy 297 } 298 299 // Set the new config orderer group to the system channel orderer group and the application group to the new application group 300 channelGroup.Groups[config.OrdererGroupKey] = systemChannelGroup.Groups[config.OrdererGroupKey] 301 channelGroup.Groups[config.ApplicationGroupKey] = applicationGroup 302 channelGroup.Values[config.ConsortiumKey] = config.TemplateConsortium(consortium.Name).Values[config.ConsortiumKey] 303 304 templateConfig, _ := utils.CreateSignedEnvelope(cb.HeaderType_CONFIG, configUpdate.ChannelId, ml.signer, &cb.ConfigEnvelope{ 305 Config: &cb.Config{ 306 ChannelGroup: channelGroup, 307 }, 308 }, msgVersion, epoch) 309 310 initializer := configtx.NewInitializer() 311 312 // This is a very hacky way to disable the sanity check logging in the policy manager 313 // for the template configuration, but it is the least invasive near a release 314 pm, ok := initializer.PolicyManager().(*policies.ManagerImpl) 315 if ok { 316 pm.SuppressSanityLogMessages = true 317 defer func() { 318 pm.SuppressSanityLogMessages = false 319 }() 320 } 321 322 return configtx.NewManagerImpl(templateConfig, initializer, nil) 323 }