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