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