github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/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/configtx" 23 configtxapi "github.com/hyperledger/fabric/common/configtx/api" 24 configvaluesapi "github.com/hyperledger/fabric/common/configvalues" 25 ordererledger "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 // Manager coordinates the creation and access of chains 37 type Manager interface { 38 // GetChain retrieves the chain support for a chain (and whether it exists) 39 GetChain(chainID string) (ChainSupport, bool) 40 41 // SystemChannelID returns the channel ID for the system channel 42 SystemChannelID() string 43 } 44 45 type configResources struct { 46 configtxapi.Manager 47 } 48 49 func (cr *configResources) SharedConfig() configvaluesapi.Orderer { 50 return cr.OrdererConfig() 51 } 52 53 type ledgerResources struct { 54 *configResources 55 ledger ordererledger.ReadWriter 56 } 57 58 type multiLedger struct { 59 chains map[string]*chainSupport 60 consenters map[string]Consenter 61 ledgerFactory ordererledger.Factory 62 signer crypto.LocalSigner 63 systemChannelID string 64 } 65 66 func getConfigTx(reader ordererledger.Reader) *cb.Envelope { 67 lastBlock := ordererledger.GetBlock(reader, reader.Height()-1) 68 index, err := utils.GetLastConfigIndexFromBlock(lastBlock) 69 if err != nil { 70 logger.Panicf("Chain did not have appropriately encoded last config in its latest block: %s", err) 71 } 72 configBlock := ordererledger.GetBlock(reader, index) 73 if configBlock == nil { 74 logger.Panicf("Config block does not exist") 75 } 76 77 return utils.ExtractEnvelopeOrPanic(configBlock, 0) 78 } 79 80 // NewManagerImpl produces an instance of a Manager 81 func NewManagerImpl(ledgerFactory ordererledger.Factory, consenters map[string]Consenter, signer crypto.LocalSigner) Manager { 82 ml := &multiLedger{ 83 chains: make(map[string]*chainSupport), 84 ledgerFactory: ledgerFactory, 85 consenters: consenters, 86 signer: signer, 87 } 88 89 existingChains := ledgerFactory.ChainIDs() 90 for _, chainID := range existingChains { 91 rl, err := ledgerFactory.GetOrCreate(chainID) 92 if err != nil { 93 logger.Fatalf("Ledger factory reported chainID %s but could not retrieve it: %s", chainID, err) 94 } 95 configTx := getConfigTx(rl) 96 if configTx == nil { 97 logger.Fatalf("Could not find config transaction for chain %s", chainID) 98 } 99 ledgerResources := ml.newLedgerResources(configTx) 100 chainID := ledgerResources.ChainID() 101 102 if ledgerResources.SharedConfig().ChainCreationPolicyNames() != nil { 103 if ml.systemChannelID != "" { 104 logger.Fatalf("There appear to be two system chains %s and %s", ml.systemChannelID, chainID) 105 } 106 chain := newChainSupport(createSystemChainFilters(ml, ledgerResources), 107 ledgerResources, 108 consenters, 109 signer) 110 logger.Infof("Starting with system channel: %s and orderer type %s", chainID, chain.SharedConfig().ConsensusType()) 111 ml.chains[string(chainID)] = chain 112 ml.systemChannelID = chainID 113 // We delay starting this chain, as it might try to copy and replace the chains map via newChain before the map is fully built 114 defer chain.start() 115 } else { 116 logger.Debugf("Starting chain: %x", chainID) 117 chain := newChainSupport(createStandardFilters(ledgerResources), 118 ledgerResources, 119 consenters, 120 signer) 121 ml.chains[string(chainID)] = chain 122 chain.start() 123 } 124 125 } 126 127 if ml.systemChannelID == "" { 128 logger.Panicf("No system chain found") 129 } 130 131 return ml 132 } 133 134 func (ml *multiLedger) SystemChannelID() string { 135 return ml.systemChannelID 136 } 137 138 // GetChain retrieves the chain support for a chain (and whether it exists) 139 func (ml *multiLedger) GetChain(chainID string) (ChainSupport, bool) { 140 cs, ok := ml.chains[chainID] 141 return cs, ok 142 } 143 144 func newConfigResources(configEnvelope *cb.ConfigEnvelope) (*configResources, error) { 145 initializer := configtx.NewInitializer() 146 configManager, err := configtx.NewManagerImpl(configEnvelope, initializer, nil) 147 if err != nil { 148 return nil, fmt.Errorf("Error unpacking config transaction: %s", err) 149 } 150 151 return &configResources{ 152 Manager: configManager, 153 }, nil 154 } 155 156 func (ml *multiLedger) newLedgerResources(configTx *cb.Envelope) *ledgerResources { 157 payload := &cb.Payload{} 158 err := proto.Unmarshal(configTx.Payload, payload) 159 if err != nil { 160 logger.Fatalf("Error unmarshaling a config transaction payload: %s", err) 161 } 162 163 configEnvelope := &cb.ConfigEnvelope{} 164 err = proto.Unmarshal(payload.Data, configEnvelope) 165 if err != nil { 166 logger.Fatalf("Error unmarshaling a config transaction to config envelope: %s", err) 167 } 168 169 configResources, err := newConfigResources(configEnvelope) 170 171 if err != nil { 172 logger.Fatalf("Error creating configtx manager and handlers: %s", err) 173 } 174 175 chainID := configResources.ChainID() 176 177 ledger, err := ml.ledgerFactory.GetOrCreate(chainID) 178 if err != nil { 179 logger.Fatalf("Error getting ledger for %s", chainID) 180 } 181 182 return &ledgerResources{ 183 configResources: configResources, 184 ledger: ledger, 185 } 186 } 187 188 func (ml *multiLedger) newChain(configtx *cb.Envelope) { 189 ledgerResources := ml.newLedgerResources(configtx) 190 ledgerResources.ledger.Append(ordererledger.CreateNextBlock(ledgerResources.ledger, []*cb.Envelope{configtx})) 191 192 // Copy the map to allow concurrent reads from broadcast/deliver while the new chainSupport is 193 newChains := make(map[string]*chainSupport) 194 for key, value := range ml.chains { 195 newChains[key] = value 196 } 197 198 cs := newChainSupport(createStandardFilters(ledgerResources), ledgerResources, ml.consenters, ml.signer) 199 chainID := ledgerResources.ChainID() 200 201 logger.Infof("Created and starting new chain %s", chainID) 202 203 newChains[string(chainID)] = cs 204 cs.start() 205 206 ml.chains = newChains 207 }