github.com/anjalikarhana/fabric@v2.1.1+incompatible/orderer/common/server/onboarding.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package server 8 9 import ( 10 "sync" 11 "time" 12 13 "github.com/golang/protobuf/proto" 14 "github.com/hyperledger/fabric-protos-go/common" 15 "github.com/hyperledger/fabric/bccsp" 16 "github.com/hyperledger/fabric/common/channelconfig" 17 "github.com/hyperledger/fabric/common/flogging" 18 "github.com/hyperledger/fabric/common/ledger/blockledger" 19 "github.com/hyperledger/fabric/internal/pkg/comm" 20 "github.com/hyperledger/fabric/internal/pkg/identity" 21 "github.com/hyperledger/fabric/orderer/common/cluster" 22 "github.com/hyperledger/fabric/orderer/common/localconfig" 23 "github.com/hyperledger/fabric/orderer/consensus/etcdraft" 24 "github.com/hyperledger/fabric/protoutil" 25 "github.com/pkg/errors" 26 ) 27 28 const ( 29 defaultReplicationBackgroundRefreshInterval = time.Minute * 5 30 replicationBackgroundInitialRefreshInterval = time.Second * 10 31 ) 32 33 type replicationInitiator struct { 34 registerChain func(chain string) 35 verifierRetriever cluster.VerifierRetriever 36 channelLister cluster.ChannelLister 37 logger *flogging.FabricLogger 38 secOpts comm.SecureOptions 39 conf *localconfig.TopLevel 40 lf cluster.LedgerFactory 41 signer identity.SignerSerializer 42 cryptoProvider bccsp.BCCSP 43 } 44 45 func (ri *replicationInitiator) replicateIfNeeded(bootstrapBlock *common.Block) { 46 if bootstrapBlock.Header.Number == 0 { 47 ri.logger.Debug("Booted with a genesis block, replication isn't an option") 48 return 49 } 50 ri.replicateNeededChannels(bootstrapBlock) 51 } 52 53 func (ri *replicationInitiator) createReplicator(bootstrapBlock *common.Block, filter func(string) bool) *cluster.Replicator { 54 consenterCert := &etcdraft.ConsenterCertificate{ 55 ConsenterCertificate: ri.secOpts.Certificate, 56 CryptoProvider: ri.cryptoProvider, 57 } 58 59 systemChannelName, err := protoutil.GetChainIDFromBlock(bootstrapBlock) 60 if err != nil { 61 ri.logger.Panicf("Failed extracting system channel name from bootstrap block: %v", err) 62 } 63 pullerConfig := cluster.PullerConfigFromTopLevelConfig(systemChannelName, ri.conf, ri.secOpts.Key, ri.secOpts.Certificate, ri.signer) 64 puller, err := cluster.BlockPullerFromConfigBlock(pullerConfig, bootstrapBlock, ri.verifierRetriever, ri.cryptoProvider) 65 if err != nil { 66 ri.logger.Panicf("Failed creating puller config from bootstrap block: %v", err) 67 } 68 puller.MaxPullBlockRetries = uint64(ri.conf.General.Cluster.ReplicationMaxRetries) 69 puller.RetryTimeout = ri.conf.General.Cluster.ReplicationRetryTimeout 70 71 replicator := &cluster.Replicator{ 72 Filter: filter, 73 LedgerFactory: ri.lf, 74 SystemChannel: systemChannelName, 75 BootBlock: bootstrapBlock, 76 Logger: ri.logger, 77 AmIPartOfChannel: consenterCert.IsConsenterOfChannel, 78 Puller: puller, 79 ChannelLister: &cluster.ChainInspector{ 80 Logger: ri.logger, 81 Puller: puller, 82 LastConfigBlock: bootstrapBlock, 83 }, 84 } 85 86 // If a custom channel lister is requested, use it 87 if ri.channelLister != nil { 88 replicator.ChannelLister = ri.channelLister 89 } 90 91 return replicator 92 } 93 94 func (ri *replicationInitiator) replicateNeededChannels(bootstrapBlock *common.Block) { 95 replicator := ri.createReplicator(bootstrapBlock, cluster.AnyChannel) 96 defer replicator.Puller.Close() 97 replicationNeeded, err := replicator.IsReplicationNeeded() 98 if err != nil { 99 ri.logger.Panicf("Failed determining whether replication is needed: %v", err) 100 } 101 102 if !replicationNeeded { 103 ri.logger.Info("Replication isn't needed") 104 return 105 } 106 107 ri.logger.Info("Will now replicate chains") 108 replicator.ReplicateChains() 109 } 110 111 // ReplicateChains replicates the given chains with the assistance of the given last system channel config block, 112 // and returns the names of the chains that were successfully replicated. 113 func (ri *replicationInitiator) ReplicateChains(lastConfigBlock *common.Block, chains []string) []string { 114 ri.logger.Info("Will now replicate chains", chains) 115 wantedChannels := make(map[string]struct{}) 116 for _, chain := range chains { 117 wantedChannels[chain] = struct{}{} 118 } 119 filter := func(channelName string) bool { 120 _, exists := wantedChannels[channelName] 121 return exists 122 } 123 replicator := ri.createReplicator(lastConfigBlock, filter) 124 replicator.DoNotPanicIfClusterNotReachable = true 125 defer replicator.Puller.Close() 126 return replicator.ReplicateChains() 127 } 128 129 type ledgerFactory struct { 130 blockledger.Factory 131 onBlockCommit cluster.BlockCommitFunc 132 } 133 134 func (lf *ledgerFactory) GetOrCreate(chainID string) (cluster.LedgerWriter, error) { 135 ledger, err := lf.Factory.GetOrCreate(chainID) 136 if err != nil { 137 return nil, err 138 } 139 interceptedLedger := &cluster.LedgerInterceptor{ 140 LedgerWriter: ledger, 141 Channel: chainID, 142 InterceptBlockCommit: lf.onBlockCommit, 143 } 144 return interceptedLedger, nil 145 } 146 147 //go:generate mockery -dir . -name ChainReplicator -case underscore -output mocks 148 149 // ChainReplicator replicates chains 150 type ChainReplicator interface { 151 // ReplicateChains replicates the given chains using the given last system channel config block. 152 // It returns the names of the chains that were successfully replicated. 153 ReplicateChains(lastConfigBlock *common.Block, chains []string) []string 154 } 155 156 // inactiveChainReplicator tracks disabled chains and replicates them upon demand 157 type inactiveChainReplicator struct { 158 registerChain func(chain string) 159 logger *flogging.FabricLogger 160 retrieveLastSysChannelConfigBlock func() *common.Block 161 replicator ChainReplicator 162 scheduleChan <-chan time.Time 163 quitChan chan struct{} 164 lock sync.RWMutex 165 chains2CreationCallbacks map[string]chainCreation 166 } 167 168 func (dc *inactiveChainReplicator) Channels() []cluster.ChannelGenesisBlock { 169 dc.lock.RLock() 170 defer dc.lock.RUnlock() 171 172 var res []cluster.ChannelGenesisBlock 173 for name, chain := range dc.chains2CreationCallbacks { 174 res = append(res, cluster.ChannelGenesisBlock{ 175 ChannelName: name, 176 GenesisBlock: chain.genesisBlock, 177 }) 178 } 179 return res 180 } 181 182 func (dc *inactiveChainReplicator) Close() {} 183 184 type chainCreation struct { 185 create func() 186 genesisBlock *common.Block 187 } 188 189 // TrackChain tracks a chain with the given name, and calls the given callback 190 // when this chain should be activated. 191 func (dc *inactiveChainReplicator) TrackChain(chain string, genesisBlock *common.Block, createChainCallback func()) { 192 dc.lock.Lock() 193 defer dc.lock.Unlock() 194 195 dc.logger.Infof("Adding %s to the set of chains to track", chain) 196 dc.chains2CreationCallbacks[chain] = chainCreation{ 197 genesisBlock: genesisBlock, 198 create: createChainCallback, 199 } 200 } 201 202 func (dc *inactiveChainReplicator) run() { 203 for { 204 select { 205 case <-dc.scheduleChan: 206 dc.replicateDisabledChains() 207 case <-dc.quitChan: 208 return 209 } 210 } 211 } 212 213 func (dc *inactiveChainReplicator) replicateDisabledChains() { 214 chains := dc.listInactiveChains() 215 if len(chains) == 0 { 216 dc.logger.Debugf("No inactive chains to try to replicate") 217 return 218 } 219 220 // For each chain, ensure we registered it into the verifier registry, otherwise 221 // we won't be able to verify its blocks. 222 for _, chain := range chains { 223 dc.registerChain(chain) 224 } 225 226 dc.logger.Infof("Found %d inactive chains: %v", len(chains), chains) 227 lastSystemChannelConfigBlock := dc.retrieveLastSysChannelConfigBlock() 228 replicatedChains := dc.replicator.ReplicateChains(lastSystemChannelConfigBlock, chains) 229 dc.logger.Infof("Successfully replicated %d chains: %v", len(replicatedChains), replicatedChains) 230 dc.lock.Lock() 231 defer dc.lock.Unlock() 232 for _, chainName := range replicatedChains { 233 chain := dc.chains2CreationCallbacks[chainName] 234 delete(dc.chains2CreationCallbacks, chainName) 235 chain.create() 236 } 237 } 238 239 func (dc *inactiveChainReplicator) stop() { 240 close(dc.quitChan) 241 } 242 243 func (dc *inactiveChainReplicator) listInactiveChains() []string { 244 dc.lock.RLock() 245 defer dc.lock.RUnlock() 246 var chains []string 247 for chain := range dc.chains2CreationCallbacks { 248 chains = append(chains, chain) 249 } 250 return chains 251 } 252 253 //go:generate mockery -dir . -name Factory -case underscore -output mocks/ 254 255 // Factory retrieves or creates new ledgers by chainID 256 type Factory interface { 257 // GetOrCreate gets an existing ledger (if it exists) 258 // or creates it if it does not 259 GetOrCreate(chainID string) (blockledger.ReadWriter, error) 260 261 // ChannelIDs returns the channel IDs the Factory is aware of 262 ChannelIDs() []string 263 264 // Close releases all resources acquired by the factory 265 Close() 266 } 267 268 type blockGetter struct { 269 ledger blockledger.Reader 270 } 271 272 func (bg *blockGetter) Block(number uint64) *common.Block { 273 return blockledger.GetBlock(bg.ledger, number) 274 } 275 276 type verifierLoader struct { 277 ledgerFactory blockledger.Factory 278 verifierFactory cluster.VerifierFactory 279 logger *flogging.FabricLogger 280 onFailure func(block *common.Block) 281 } 282 283 type verifiersByChannel map[string]cluster.BlockVerifier 284 285 func (vl *verifierLoader) loadVerifiers() verifiersByChannel { 286 res := make(verifiersByChannel) 287 288 for _, channel := range vl.ledgerFactory.ChannelIDs() { 289 v := vl.loadVerifier(channel) 290 if v == nil { 291 continue 292 } 293 res[channel] = v 294 } 295 296 return res 297 } 298 299 func (vl *verifierLoader) loadVerifier(chain string) cluster.BlockVerifier { 300 ledger, err := vl.ledgerFactory.GetOrCreate(chain) 301 if err != nil { 302 vl.logger.Panicf("Failed obtaining ledger for channel %s", chain) 303 } 304 305 blockRetriever := &blockGetter{ledger: ledger} 306 height := ledger.Height() 307 if height == 0 { 308 vl.logger.Errorf("Channel %s has no blocks, skipping it", chain) 309 return nil 310 } 311 lastBlockIndex := height - 1 312 lastBlock := blockRetriever.Block(lastBlockIndex) 313 if lastBlock == nil { 314 vl.logger.Panicf("Failed retrieving block [%d] for channel %s", lastBlockIndex, chain) 315 } 316 317 lastConfigBlock, err := cluster.LastConfigBlock(lastBlock, blockRetriever) 318 if err != nil { 319 vl.logger.Panicf("Failed retrieving config block [%d] for channel %s", lastBlockIndex, chain) 320 } 321 conf, err := cluster.ConfigFromBlock(lastConfigBlock) 322 if err != nil { 323 vl.onFailure(lastConfigBlock) 324 vl.logger.Panicf("Failed extracting configuration for channel %s from block [%d]: %v", 325 chain, lastConfigBlock.Header.Number, err) 326 } 327 328 verifier, err := vl.verifierFactory.VerifierFromConfig(conf, chain) 329 if err != nil { 330 vl.onFailure(lastConfigBlock) 331 vl.logger.Panicf("Failed creating verifier for channel %s from block [%d]: %v", chain, lastBlockIndex, err) 332 } 333 vl.logger.Infof("Loaded verifier for channel %s from config block at index %d", chain, lastBlockIndex) 334 return verifier 335 } 336 337 // ValidateBootstrapBlock returns whether this block can be used as a bootstrap block. 338 // A bootstrap block is a block of a system channel, and needs to have a ConsortiumsConfig. 339 func ValidateBootstrapBlock(block *common.Block, bccsp bccsp.BCCSP) error { 340 if block == nil { 341 return errors.New("nil block") 342 } 343 344 if block.Data == nil || len(block.Data.Data) == 0 { 345 return errors.New("empty block data") 346 } 347 348 firstTransaction := &common.Envelope{} 349 if err := proto.Unmarshal(block.Data.Data[0], firstTransaction); err != nil { 350 return errors.Wrap(err, "failed extracting envelope from block") 351 } 352 353 bundle, err := channelconfig.NewBundleFromEnvelope(firstTransaction, bccsp) 354 if err != nil { 355 return err 356 } 357 358 _, exists := bundle.ConsortiumsConfig() 359 if !exists { 360 return errors.New("the block isn't a system channel block because it lacks ConsortiumsConfig") 361 } 362 return nil 363 }