github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/orderer/common/multichannel/registrar.go (about) 1 /* 2 Copyright hechain. 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 "path/filepath" 15 "strings" 16 "sync" 17 18 "github.com/golang/protobuf/proto" 19 "github.com/hechain20/hechain/bccsp" 20 "github.com/hechain20/hechain/common/channelconfig" 21 "github.com/hechain20/hechain/common/configtx" 22 "github.com/hechain20/hechain/common/flogging" 23 "github.com/hechain20/hechain/common/ledger/blockledger" 24 "github.com/hechain20/hechain/common/metrics" 25 "github.com/hechain20/hechain/internal/pkg/identity" 26 "github.com/hechain20/hechain/orderer/common/blockcutter" 27 "github.com/hechain20/hechain/orderer/common/cluster" 28 "github.com/hechain20/hechain/orderer/common/filerepo" 29 "github.com/hechain20/hechain/orderer/common/follower" 30 "github.com/hechain20/hechain/orderer/common/localconfig" 31 "github.com/hechain20/hechain/orderer/common/msgprocessor" 32 "github.com/hechain20/hechain/orderer/common/types" 33 "github.com/hechain20/hechain/orderer/consensus" 34 "github.com/hechain20/hechain/orderer/consensus/etcdraft" 35 "github.com/hechain20/hechain/protoutil" 36 cb "github.com/hyperledger/fabric-protos-go/common" 37 "github.com/pkg/errors" 38 ) 39 40 const ( 41 msgVersion = int32(0) 42 epoch = 0 43 ) 44 45 var logger = flogging.MustGetLogger("orderer.commmon.multichannel") 46 47 // Registrar serves as a point of access and control for the individual channel resources. 48 type Registrar struct { 49 config localconfig.TopLevel 50 51 lock sync.RWMutex 52 chains map[string]*ChainSupport 53 followers map[string]*follower.Chain 54 // existence indicates removal is in-progress or failed 55 // when failed, the status will indicate failed all other states 56 // denote an in-progress removal 57 pendingRemoval map[string]consensus.StaticStatusReporter 58 systemChannelID string 59 systemChannel *ChainSupport 60 61 consenters map[string]consensus.Consenter 62 ledgerFactory blockledger.Factory 63 signer identity.SignerSerializer 64 blockcutterMetrics *blockcutter.Metrics 65 templator msgprocessor.ChannelConfigTemplator 66 callbacks []channelconfig.BundleActor 67 bccsp bccsp.BCCSP 68 clusterDialer *cluster.PredicateDialer 69 channelParticipationMetrics *Metrics 70 71 joinBlockFileRepo *filerepo.Repo 72 } 73 74 // ConfigBlockOrPanic retrieves the last configuration block from the given ledger. 75 // Panics on failure. 76 func ConfigBlockOrPanic(reader blockledger.Reader) *cb.Block { 77 lastBlock, err := blockledger.GetBlockByNumber(reader, reader.Height()-1) 78 if err != nil { 79 logger.Panicw("Failed to retrieve block", "blockNum", reader.Height()-1, "error", err) 80 } 81 index, err := protoutil.GetLastConfigIndexFromBlock(lastBlock) 82 if err != nil { 83 logger.Panicw("Chain did not have appropriately encoded last config in its latest block", "error", err) 84 } 85 configBlock, err := blockledger.GetBlockByNumber(reader, index) 86 if err != nil { 87 logger.Panicw("Failed to retrieve config block", "blockNum", index, "error", err) 88 } 89 return configBlock 90 } 91 92 func configTx(reader blockledger.Reader) *cb.Envelope { 93 return protoutil.ExtractEnvelopeOrPanic(ConfigBlockOrPanic(reader), 0) 94 } 95 96 // NewRegistrar produces an instance of a *Registrar. 97 func NewRegistrar( 98 config localconfig.TopLevel, 99 ledgerFactory blockledger.Factory, 100 signer identity.SignerSerializer, 101 metricsProvider metrics.Provider, 102 bccsp bccsp.BCCSP, 103 clusterDialer *cluster.PredicateDialer, 104 callbacks ...channelconfig.BundleActor) *Registrar { 105 r := &Registrar{ 106 config: config, 107 chains: make(map[string]*ChainSupport), 108 followers: make(map[string]*follower.Chain), 109 pendingRemoval: make(map[string]consensus.StaticStatusReporter), 110 ledgerFactory: ledgerFactory, 111 signer: signer, 112 blockcutterMetrics: blockcutter.NewMetrics(metricsProvider), 113 callbacks: callbacks, 114 bccsp: bccsp, 115 clusterDialer: clusterDialer, 116 channelParticipationMetrics: NewMetrics(metricsProvider), 117 } 118 119 if config.ChannelParticipation.Enabled { 120 var err error 121 r.joinBlockFileRepo, err = InitJoinBlockFileRepo(&r.config) 122 if err != nil { 123 logger.Panicf("Error initializing joinblock file repo: %s", err) 124 } 125 } 126 127 return r 128 } 129 130 // InitJoinBlockFileRepo initialize the channel participation API joinblock file repo. This creates 131 // the fileRepoDir on the filesystem if it does not already exist. 132 func InitJoinBlockFileRepo(config *localconfig.TopLevel) (*filerepo.Repo, error) { 133 fileRepoDir := filepath.Join(config.FileLedger.Location, "pendingops") 134 logger.Infof("Channel Participation API enabled, registrar initializing with file repo %s", fileRepoDir) 135 136 joinBlockFileRepo, err := filerepo.New(fileRepoDir, "join") 137 if err != nil { 138 return nil, err 139 } 140 return joinBlockFileRepo, nil 141 } 142 143 func (r *Registrar) Initialize(consenters map[string]consensus.Consenter) { 144 r.init(consenters) 145 146 r.lock.Lock() 147 defer r.lock.Unlock() 148 r.startChannels() 149 } 150 151 func (r *Registrar) init(consenters map[string]consensus.Consenter) { 152 r.consenters = consenters 153 154 // Discover and load join-blocks. If there is a join-block, there must be a ledger; if there is none, create it. 155 // channelsWithJoinBlock maps channelID to a join-block. 156 channelsWithJoinBlock := r.loadJoinBlocks() 157 158 // Discover all ledgers. This should already include all channels with join blocks as well. 159 // Make sure there are no empty ledgers without a corresponding join-block. 160 existingChannels := r.discoverLedgers(channelsWithJoinBlock) 161 162 // Scan for and initialize the system channel, if it exists. 163 // Note that there may be channels with empty ledgers, but always with a join block. 164 r.initSystemChannel(existingChannels) 165 166 // Initialize application channels, by creating either a consensus.Chain or a follower.Chain. 167 if r.systemChannelID == "" { 168 r.initAppChannels(existingChannels, channelsWithJoinBlock) 169 } else { 170 r.initAppChannelsWhenSystemChannelExists(existingChannels) 171 } 172 } 173 174 // startChannels starts internal go-routines in chains and followers. 175 // Since these go-routines may call-back on the Registrar, this must be protected with a lock. 176 func (r *Registrar) startChannels() { 177 for _, chainSupport := range r.chains { 178 chainSupport.start() 179 } 180 for _, fChain := range r.followers { 181 fChain.Start() 182 } 183 184 if r.systemChannelID == "" { 185 logger.Infof("Registrar initializing without a system channel, number of application channels: %d, with %d consensus.Chain(s) and %d follower.Chain(s)", 186 len(r.chains)+len(r.followers), len(r.chains), len(r.followers)) 187 } 188 } 189 190 func (r *Registrar) discoverLedgers(channelsWithJoinBlock map[string]*cb.Block) []string { 191 // Discover all ledgers. This should already include all channels with join blocks as well. 192 existingChannels := r.ledgerFactory.ChannelIDs() 193 194 for _, channelID := range existingChannels { 195 rl, err := r.ledgerFactory.GetOrCreate(channelID) 196 if err != nil { 197 logger.Panicf("Ledger factory reported channelID %s but could not retrieve it: %s", channelID, err) 198 } 199 // Prune empty ledgers without a join block 200 if rl.Height() == 0 { 201 if _, ok := channelsWithJoinBlock[channelID]; !ok { 202 logger.Warnf("Channel '%s' has an empty ledger without a join-block, removing it", channelID) 203 if err := r.ledgerFactory.Remove(channelID); err != nil { 204 logger.Panicf("Ledger factory failed to remove empty ledger '%s', error: %s", channelID, err) 205 } 206 } 207 } 208 } 209 210 return r.ledgerFactory.ChannelIDs() 211 } 212 213 // initSystemChannel scan for and initialize the system channel, if it exists. 214 func (r *Registrar) initSystemChannel(existingChannels []string) { 215 for _, channelID := range existingChannels { 216 rl, err := r.ledgerFactory.GetOrCreate(channelID) 217 if err != nil { 218 logger.Panicf("Ledger factory reported channelID %s but could not retrieve it: %s", channelID, err) 219 } 220 221 if rl.Height() == 0 { 222 // At this point in the initialization flow the system channel cannot be with height==0 and a join-block. 223 // Even when the system channel is joined via the channel participation API, on-boarding is performed 224 // prior to this point. Therefore, this is an application channel. 225 continue // Skip application channels 226 } 227 228 configTransaction := configTx(rl) 229 if configTransaction == nil { 230 logger.Panic("Programming error, configTransaction should never be nil here") 231 } 232 ledgerResources, err := r.newLedgerResources(configTransaction) 233 if err != nil { 234 logger.Panicf("Error creating ledger resources: %s", err) 235 } 236 channelID := ledgerResources.ConfigtxValidator().ChannelID() 237 238 if _, ok := ledgerResources.ConsortiumsConfig(); !ok { 239 continue // Skip application channels 240 } 241 242 if r.systemChannelID != "" { 243 logger.Panicf("There appear to be two system channels %s and %s", r.systemChannelID, channelID) 244 } 245 246 chain, err := newChainSupport(r, ledgerResources, r.consenters, r.signer, r.blockcutterMetrics, r.bccsp) 247 if err != nil { 248 logger.Panicf("Error creating chain support: %s", err) 249 } 250 r.templator = msgprocessor.NewDefaultTemplator(chain, r.bccsp) 251 chain.Processor = msgprocessor.NewSystemChannel( 252 chain, 253 r.templator, 254 msgprocessor.CreateSystemChannelFilters(r.config, r, chain, chain.MetadataValidator), 255 r.bccsp, 256 ) 257 258 // Retrieve genesis block to log its hash. See FAB-5450 for the purpose 259 genesisBlock := ledgerResources.Block(0) 260 if genesisBlock == nil { 261 logger.Panicf("Error reading genesis block of system channel '%s'", channelID) 262 } 263 logger.Infof( 264 "Starting system channel '%s' with genesis block hash %x and orderer type %s", 265 channelID, 266 protoutil.BlockHeaderHash(genesisBlock.Header), //lint:ignore SA5011 logs and panics above 267 chain.SharedConfig().ConsensusType(), 268 ) 269 270 r.chains[channelID] = chain 271 r.systemChannelID = channelID 272 r.systemChannel = chain 273 } 274 } 275 276 // initAppChannels initializes application channels, assuming that the system channel does NOT exist. 277 // This implies that the orderer is using the channel participation API for joins (channel creation). 278 func (r *Registrar) initAppChannels(existingChannels []string, channelsWithJoinBlock map[string]*cb.Block) { 279 // init app channels with join-blocks 280 for channelID, joinBlock := range channelsWithJoinBlock { 281 ledgerRes, clusterConsenter, err := r.initLedgerResourcesClusterConsenter(joinBlock) 282 if err != nil { 283 logger.Panicf("Error: %s, channel: %s", err, channelID) 284 } 285 286 isMember, err := clusterConsenter.IsChannelMember(joinBlock) 287 if err != nil { 288 logger.Panicf("Failed to determine cluster membership from join-block, channel: %s, error: %s", channelID, err) 289 } 290 291 if joinBlock.Header.Number == 0 && isMember { 292 if _, _, err := r.createAsMember(ledgerRes, joinBlock, channelID); err != nil { 293 logger.Panicf("Failed to createAsMember, error: %s", err) 294 } 295 if err := r.removeJoinBlock(channelID); err != nil { 296 logger.Panicf("Failed to remove join-block, channel: %s, error: %s", channelID, err) 297 } 298 } else { 299 if _, _, err = r.createFollower(ledgerRes, clusterConsenter, joinBlock, channelID); err != nil { 300 logger.Panicf("Failed to createFollower, error: %s", err) 301 } 302 } 303 } 304 305 // init app channels without join-blocks 306 for _, channelID := range existingChannels { 307 if _, withJoinBlock := channelsWithJoinBlock[channelID]; withJoinBlock { 308 continue // Skip channels with join-blocks, since they were already initialized above. 309 } 310 311 rl, err := r.ledgerFactory.GetOrCreate(channelID) 312 if err != nil { 313 logger.Panicf("Ledger factory reported channelID %s but could not retrieve it: %s", channelID, err) 314 } 315 316 configBlock := ConfigBlockOrPanic(rl) 317 configTx := protoutil.ExtractEnvelopeOrPanic(configBlock, 0) 318 if configTx == nil { 319 logger.Panic("Programming error, configTx should never be nil here") 320 } 321 ledgerRes, err := r.newLedgerResources(configTx) 322 if err != nil { 323 logger.Panicf("Error creating ledger resources: %s", err) 324 } 325 326 ordererConfig, _ := ledgerRes.OrdererConfig() 327 consenter, foundConsenter := r.consenters[ordererConfig.ConsensusType()] 328 if !foundConsenter { 329 logger.Panicf("Failed to find a consenter for consensus type: %s", ordererConfig.ConsensusType()) 330 } 331 332 clusterConsenter, ok := consenter.(consensus.ClusterConsenter) 333 if !ok { 334 logger.Panic("clusterConsenter is not a consensus.ClusterConsenter") 335 } 336 337 isMember, err := clusterConsenter.IsChannelMember(configBlock) 338 if err != nil { 339 logger.Panicf("Failed to determine cluster membership from config-block, error: %s", err) 340 } 341 342 if isMember { 343 chainSupport, err := newChainSupport(r, ledgerRes, r.consenters, r.signer, r.blockcutterMetrics, r.bccsp) 344 if err != nil { 345 logger.Panicf("Failed to create chain support for channel '%s', error: %s", channelID, err) 346 } 347 r.chains[channelID] = chainSupport 348 } else { 349 _, _, err := r.createFollower(ledgerRes, clusterConsenter, nil, channelID) 350 if err != nil { 351 logger.Panicf("Failed to create follower for channel '%s', error: %s", channelID, err) 352 } 353 } 354 } 355 } 356 357 // initAppChannelsWhenSystemChannelExists initializes application channels, assuming that the system channel exists. 358 // This implies that the channel participation API is not used for joins (channel creation). Therefore, there are no 359 // join-blocks, and follower.Chain(s) are never created. The call to newChainSupport creates a consensus.Chain of the 360 // appropriate type. 361 func (r *Registrar) initAppChannelsWhenSystemChannelExists(existingChannels []string) { 362 for _, channelID := range existingChannels { 363 if channelID == r.systemChannelID { 364 continue // Skip system channel 365 } 366 rl, err := r.ledgerFactory.GetOrCreate(channelID) 367 if err != nil { 368 logger.Panicf("Ledger factory reported channelID %s but could not retrieve it: %s", channelID, err) 369 } 370 371 configTxEnv := configTx(rl) 372 if configTxEnv == nil { 373 logger.Panic("Programming error, configTxEnv should never be nil here") 374 } 375 ledgerRes, err := r.newLedgerResources(configTxEnv) 376 if err != nil { 377 logger.Panicf("Error creating ledger resources: %s", err) 378 } 379 380 chainSupport, err := newChainSupport(r, ledgerRes, r.consenters, r.signer, r.blockcutterMetrics, r.bccsp) 381 if err != nil { 382 logger.Panicf("Failed to create chain support for channel '%s', error: %s", channelID, err) 383 } 384 r.chains[channelID] = chainSupport 385 } 386 } 387 388 func (r *Registrar) initLedgerResourcesClusterConsenter(configBlock *cb.Block) (*ledgerResources, consensus.ClusterConsenter, error) { 389 configEnv, err := protoutil.ExtractEnvelope(configBlock, 0) 390 if err != nil { 391 return nil, nil, errors.WithMessagef(err, "failed extracting config envelope from block") 392 } 393 394 ledgerRes, err := r.newLedgerResources(configEnv) 395 if err != nil { 396 return nil, nil, errors.WithMessagef(err, "failed creating ledger resources") 397 } 398 399 ordererConfig, _ := ledgerRes.OrdererConfig() 400 consenter, foundConsenter := r.consenters[ordererConfig.ConsensusType()] 401 if !foundConsenter { 402 return nil, nil, errors.Errorf("failed to find a consenter for consensus type: %s", ordererConfig.ConsensusType()) 403 } 404 405 clusterConsenter, ok := consenter.(consensus.ClusterConsenter) 406 if !ok { 407 return nil, nil, errors.New("failed cast: clusterConsenter is not a consensus.ClusterConsenter") 408 } 409 410 return ledgerRes, clusterConsenter, nil 411 } 412 413 // SystemChannelID returns the ChannelID for the system channel. 414 func (r *Registrar) SystemChannelID() string { 415 r.lock.RLock() 416 defer r.lock.RUnlock() 417 return r.systemChannelID 418 } 419 420 // SystemChannel returns the ChainSupport for the system channel. 421 func (r *Registrar) SystemChannel() *ChainSupport { 422 r.lock.RLock() 423 defer r.lock.RUnlock() 424 return r.systemChannel 425 } 426 427 // BroadcastChannelSupport returns the message channel header, whether the message is a config update 428 // and the channel resources for a message or an error if the message is not a message which can 429 // be processed directly (like CONFIG and ORDERER_TRANSACTION messages) 430 func (r *Registrar) BroadcastChannelSupport(msg *cb.Envelope) (*cb.ChannelHeader, bool, *ChainSupport, error) { 431 chdr, err := protoutil.ChannelHeader(msg) 432 if err != nil { 433 return nil, false, nil, errors.WithMessage(err, "could not determine channel ID") 434 } 435 436 cs := r.GetChain(chdr.ChannelId) 437 // New channel creation 438 if cs == nil { 439 sysChan := r.SystemChannel() 440 if sysChan == nil { 441 return nil, false, nil, errors.New("channel creation request not allowed because the orderer system channel is not defined") 442 } 443 cs = sysChan 444 } 445 446 isConfig := false 447 switch cs.ClassifyMsg(chdr) { 448 case msgprocessor.ConfigUpdateMsg: 449 isConfig = true 450 case msgprocessor.ConfigMsg: 451 return chdr, false, nil, errors.New("message is of type that cannot be processed directly") 452 default: 453 } 454 455 return chdr, isConfig, cs, nil 456 } 457 458 // GetConsensusChain retrieves the consensus.Chain of the channel, if it exists. 459 func (r *Registrar) GetConsensusChain(chainID string) consensus.Chain { 460 r.lock.RLock() 461 defer r.lock.RUnlock() 462 463 cs, exists := r.chains[chainID] 464 if !exists { 465 return nil 466 } 467 468 return cs.Chain 469 } 470 471 // GetChain retrieves the chain support for a chain if it exists. 472 func (r *Registrar) GetChain(chainID string) *ChainSupport { 473 r.lock.RLock() 474 defer r.lock.RUnlock() 475 476 return r.chains[chainID] 477 } 478 479 // GetFollower retrieves the follower.Chain if it exists. 480 func (r *Registrar) GetFollower(chainID string) *follower.Chain { 481 r.lock.RLock() 482 defer r.lock.RUnlock() 483 484 return r.followers[chainID] 485 } 486 487 func (r *Registrar) newLedgerResources(configTx *cb.Envelope) (*ledgerResources, error) { 488 payload, err := protoutil.UnmarshalPayload(configTx.Payload) 489 if err != nil { 490 return nil, errors.WithMessage(err, "error umarshaling envelope to payload") 491 } 492 493 if payload.Header == nil { 494 return nil, errors.New("missing channel header") 495 } 496 497 chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader) 498 if err != nil { 499 return nil, errors.WithMessage(err, "error unmarshalling channel header") 500 } 501 502 configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data) 503 if err != nil { 504 return nil, errors.WithMessage(err, "error umarshaling config envelope from payload data") 505 } 506 507 bundle, err := channelconfig.NewBundle(chdr.ChannelId, configEnvelope.Config, r.bccsp) 508 if err != nil { 509 return nil, errors.WithMessage(err, "error creating channelconfig bundle") 510 } 511 512 err = checkResources(bundle) 513 if err != nil { 514 return nil, errors.WithMessagef(err, "error checking bundle for channel: %s", chdr.ChannelId) 515 } 516 517 ledger, err := r.ledgerFactory.GetOrCreate(chdr.ChannelId) 518 if err != nil { 519 return nil, errors.WithMessagef(err, "error getting ledger for channel: %s", chdr.ChannelId) 520 } 521 522 return &ledgerResources{ 523 configResources: &configResources{ 524 mutableResources: channelconfig.NewBundleSource(bundle, r.callbacks...), 525 bccsp: r.bccsp, 526 }, 527 ReadWriter: ledger, 528 }, nil 529 } 530 531 // CreateChain makes the Registrar create a consensus.Chain with the given name. 532 func (r *Registrar) CreateChain(chainName string) { 533 lf, err := r.ledgerFactory.GetOrCreate(chainName) 534 if err != nil { 535 logger.Panicf("Failed obtaining ledger factory for %s: %v", chainName, err) 536 } 537 chain := r.GetChain(chainName) 538 if chain != nil { 539 logger.Infof("A chain of type %T for channel %s already exists. "+ 540 "Halting it.", chain.Chain, chainName) 541 r.lock.Lock() 542 chain.Halt() 543 delete(r.chains, chainName) 544 r.lock.Unlock() 545 } 546 r.newChain(configTx(lf)) 547 } 548 549 func (r *Registrar) newChain(configtx *cb.Envelope) { 550 r.lock.Lock() 551 defer r.lock.Unlock() 552 553 channelName, err := channelNameFromConfigTx(configtx) 554 if err != nil { 555 logger.Warnf("Failed extracting channel name: %v", err) 556 return 557 } 558 559 // fixes https://github.com/hechain20/hechain/issues/2931 560 if existingChain, exists := r.chains[channelName]; exists { 561 if _, isRaftChain := existingChain.Chain.(*etcdraft.Chain); isRaftChain { 562 logger.Infof("Channel %s already created, skipping its creation", channelName) 563 return 564 } 565 } 566 567 cs := r.createNewChain(configtx) 568 cs.start() 569 logger.Infof("Created and started new channel %s", cs.ChannelID()) 570 } 571 572 func (r *Registrar) createNewChain(configtx *cb.Envelope) *ChainSupport { 573 ledgerResources, err := r.newLedgerResources(configtx) 574 if err != nil { 575 logger.Panicf("Error creating ledger resources: %s", err) 576 } 577 578 // If we have no blocks, we need to create the genesis block ourselves. 579 if ledgerResources.Height() == 0 { 580 if err := ledgerResources.Append(blockledger.CreateNextBlock(ledgerResources, []*cb.Envelope{configtx})); err != nil { 581 logger.Panicf("Error appending genesis block to ledger: %s", err) 582 } 583 } 584 cs, err := newChainSupport(r, ledgerResources, r.consenters, r.signer, r.blockcutterMetrics, r.bccsp) 585 if err != nil { 586 logger.Panicf("Error creating chain support: %s", err) 587 } 588 589 chainID := ledgerResources.ConfigtxValidator().ChannelID() 590 r.chains[chainID] = cs 591 592 return cs 593 } 594 595 // SwitchFollowerToChain creates a consensus.Chain from the tip of the ledger, and removes the follower. 596 // It is called when a follower detects a config block that indicates cluster membership and halts, transferring 597 // execution to the consensus.Chain. 598 func (r *Registrar) SwitchFollowerToChain(channelID string) { 599 r.lock.Lock() 600 defer r.lock.Unlock() 601 602 lf, err := r.ledgerFactory.GetOrCreate(channelID) 603 if err != nil { 604 logger.Panicf("Failed obtaining ledger factory for channel %s: %v", channelID, err) 605 } 606 607 if _, chainExists := r.chains[channelID]; chainExists { 608 logger.Panicf("Programming error, channel already exists: %s", channelID) 609 } 610 611 delete(r.followers, channelID) 612 logger.Debugf("Removed follower for channel %s", channelID) 613 cs := r.createNewChain(configTx(lf)) 614 if err := r.removeJoinBlock(channelID); err != nil { 615 logger.Panicf("Failed removing join-block for channel: %s: %v", channelID, err) 616 } 617 cs.start() 618 logger.Infof("Created and started channel %s", cs.ChannelID()) 619 } 620 621 // SwitchChainToFollower creates a follower.Chain from the tip of the ledger and removes the consensus.Chain. 622 // It is called when an etcdraft.Chain detects it was evicted from the cluster (i.e. removed from the consenters set) 623 // and halts, transferring execution to the follower.Chain. 624 func (r *Registrar) SwitchChainToFollower(channelName string) { 625 r.lock.Lock() 626 defer r.lock.Unlock() 627 628 if _, chainExists := r.chains[channelName]; !chainExists { 629 logger.Infof("Channel %s consenter was removed", channelName) 630 return 631 } 632 633 if _, followerExists := r.followers[channelName]; followerExists { 634 logger.Panicf("Programming error, both a follower.Chain and a consensus.Chain exist, channel: %s", channelName) 635 } 636 637 rl, err := r.ledgerFactory.GetOrCreate(channelName) 638 if err != nil { 639 logger.Panicf("Failed obtaining ledger factory for %s: %v", channelName, err) 640 } 641 642 configBlock := ConfigBlockOrPanic(rl) 643 ledgerRes, clusterConsenter, err := r.initLedgerResourcesClusterConsenter(configBlock) 644 if err != nil { 645 logger.Panicf("Error initializing ledgerResources & clusterConsenter: %s", err) 646 } 647 648 delete(r.chains, channelName) 649 logger.Debugf("Removed consensus.Chain for channel %s", channelName) 650 651 fChain, _, err := r.createFollower(ledgerRes, clusterConsenter, nil, channelName) 652 if err != nil { 653 logger.Panicf("Failed to create follower.Chain for channel '%s', error: %s", channelName, err) 654 } 655 fChain.Start() 656 657 logger.Infof("Created and started a follower.Chain for channel %s", channelName) 658 } 659 660 // ChannelsCount returns the count of the current total number of channels. 661 func (r *Registrar) ChannelsCount() int { 662 r.lock.RLock() 663 defer r.lock.RUnlock() 664 665 return len(r.chains) + len(r.followers) 666 } 667 668 // NewChannelConfig produces a new template channel configuration based on the system channel's current config. 669 func (r *Registrar) NewChannelConfig(envConfigUpdate *cb.Envelope) (channelconfig.Resources, error) { 670 return r.templator.NewChannelConfig(envConfigUpdate) 671 } 672 673 // CreateBundle calls channelconfig.NewBundle 674 func (r *Registrar) CreateBundle(channelID string, config *cb.Config) (channelconfig.Resources, error) { 675 return channelconfig.NewBundle(channelID, config, r.bccsp) 676 } 677 678 // ChannelList returns a slice of ChannelInfoShort containing all application channels (excluding the system 679 // channel), and ChannelInfoShort of the system channel (nil if does not exist). 680 // The URL fields are empty, and are to be completed by the caller. 681 func (r *Registrar) ChannelList() types.ChannelList { 682 r.lock.RLock() 683 defer r.lock.RUnlock() 684 685 list := types.ChannelList{} 686 687 if r.systemChannelID != "" { 688 list.SystemChannel = &types.ChannelInfoShort{Name: r.systemChannelID} 689 } 690 for name := range r.chains { 691 if name == r.systemChannelID { 692 continue 693 } 694 list.Channels = append(list.Channels, types.ChannelInfoShort{Name: name}) 695 } 696 for name := range r.followers { 697 list.Channels = append(list.Channels, types.ChannelInfoShort{Name: name}) 698 } 699 700 for c := range r.pendingRemoval { 701 list.Channels = append(list.Channels, types.ChannelInfoShort{ 702 Name: c, 703 }) 704 } 705 706 return list 707 } 708 709 // ChannelInfo provides extended status information about a channel. 710 // The URL field is empty, and is to be completed by the caller. 711 func (r *Registrar) ChannelInfo(channelID string) (types.ChannelInfo, error) { 712 r.lock.RLock() 713 defer r.lock.RUnlock() 714 715 info := types.ChannelInfo{Name: channelID} 716 717 if c, ok := r.chains[channelID]; ok { 718 info.Height = c.Height() 719 info.ConsensusRelation, info.Status = c.StatusReport() 720 return info, nil 721 } 722 723 if f, ok := r.followers[channelID]; ok { 724 info.Height = f.Height() 725 info.ConsensusRelation, info.Status = f.StatusReport() 726 return info, nil 727 } 728 729 status, ok := r.pendingRemoval[channelID] 730 if ok { 731 return types.ChannelInfo{ 732 Name: channelID, 733 ConsensusRelation: status.ConsensusRelation, 734 Status: status.Status, 735 }, nil 736 } 737 738 return types.ChannelInfo{}, types.ErrChannelNotExist 739 } 740 741 // JoinChannel instructs the orderer to create a channel and join it with the provided config block. 742 // The URL field is empty, and is to be completed by the caller. 743 func (r *Registrar) JoinChannel(channelID string, configBlock *cb.Block, isAppChannel bool) (info types.ChannelInfo, err error) { 744 r.lock.Lock() 745 defer r.lock.Unlock() 746 747 if status, ok := r.pendingRemoval[channelID]; ok { 748 if status.Status == types.StatusFailed { 749 return types.ChannelInfo{}, types.ErrChannelRemovalFailure 750 } 751 return types.ChannelInfo{}, types.ErrChannelPendingRemoval 752 } 753 754 if r.systemChannelID != "" { 755 return types.ChannelInfo{}, types.ErrSystemChannelExists 756 } 757 758 if _, ok := r.chains[channelID]; ok { 759 return types.ChannelInfo{}, types.ErrChannelAlreadyExists 760 } 761 762 if _, ok := r.followers[channelID]; ok { 763 return types.ChannelInfo{}, types.ErrChannelAlreadyExists 764 } 765 766 if !isAppChannel && len(r.chains) > 0 { 767 return types.ChannelInfo{}, types.ErrAppChannelsAlreadyExists 768 } 769 770 defer func() { 771 if err != nil { 772 if err2 := r.ledgerFactory.Remove(channelID); err2 != nil { 773 logger.Warningf("Failed to cleanup ledger: %v", err2) 774 } 775 } 776 }() 777 ledgerRes, clusterConsenter, err := r.initLedgerResourcesClusterConsenter(configBlock) 778 if err != nil { 779 return types.ChannelInfo{}, err 780 } 781 782 blockBytes, err := proto.Marshal(configBlock) 783 if err != nil { 784 return types.ChannelInfo{}, errors.Wrap(err, "failed marshaling joinblock") 785 } 786 787 if err := r.joinBlockFileRepo.Save(channelID, blockBytes); err != nil { 788 return types.ChannelInfo{}, errors.WithMessagef(err, "failed saving joinblock to file repo for channel %s", channelID) 789 } 790 defer func() { 791 if err != nil { 792 if err2 := r.removeJoinBlock(channelID); err2 != nil { 793 logger.Warningf("Failed to cleanup joinblock for channel %s: %v", channelID, err2) 794 } 795 } 796 }() 797 798 if !isAppChannel { 799 info, err := r.joinSystemChannel(ledgerRes, clusterConsenter, configBlock, channelID) 800 return info, err 801 } 802 803 isMember, err := clusterConsenter.IsChannelMember(configBlock) 804 if err != nil { 805 return types.ChannelInfo{}, errors.WithMessage(err, "failed to determine cluster membership from join-block") 806 } 807 808 if configBlock.Header.Number == 0 && isMember { 809 chain, info, err := r.createAsMember(ledgerRes, configBlock, channelID) 810 if err == nil { 811 if err := r.removeJoinBlock(channelID); err != nil { 812 return types.ChannelInfo{}, err 813 } 814 chain.start() 815 } 816 return info, err 817 } 818 819 fChain, info, err := r.createFollower(ledgerRes, clusterConsenter, configBlock, channelID) 820 if err != nil { 821 return info, errors.WithMessage(err, "failed to create follower") 822 } 823 824 fChain.Start() 825 logger.Infof("Joining channel: %v", info) 826 return info, err 827 } 828 829 func (r *Registrar) createAsMember(ledgerRes *ledgerResources, configBlock *cb.Block, channelID string) (*ChainSupport, types.ChannelInfo, error) { 830 if ledgerRes.Height() == 0 { 831 if err := ledgerRes.Append(configBlock); err != nil { 832 return nil, types.ChannelInfo{}, errors.WithMessage(err, "failed to append join block to the ledger") 833 } 834 } 835 chain, err := newChainSupport( 836 r, 837 ledgerRes, 838 r.consenters, 839 r.signer, 840 r.blockcutterMetrics, 841 r.bccsp, 842 ) 843 if err != nil { 844 return nil, types.ChannelInfo{}, errors.WithMessage(err, "failed to create chain support") 845 } 846 847 info := types.ChannelInfo{ 848 Name: channelID, 849 URL: "", 850 Height: ledgerRes.Height(), 851 } 852 info.ConsensusRelation, info.Status = chain.StatusReport() 853 r.chains[channelID] = chain 854 855 logger.Infof("Joining channel: %v", info) 856 return chain, info, nil 857 } 858 859 // createFollower created a follower.Chain, puts it in the map, but does not start it. 860 func (r *Registrar) createFollower( 861 ledgerRes *ledgerResources, 862 clusterConsenter consensus.ClusterConsenter, 863 joinBlock *cb.Block, 864 channelID string, 865 ) (*follower.Chain, types.ChannelInfo, error) { 866 fLog := flogging.MustGetLogger("orderer.commmon.follower") 867 blockPullerCreator, err := follower.NewBlockPullerCreator( 868 channelID, fLog, r.signer, r.clusterDialer, r.config.General.Cluster, r.bccsp) 869 if err != nil { 870 return nil, types.ChannelInfo{}, errors.WithMessagef(err, "failed to create BlockPullerFactory for channel %s", channelID) 871 } 872 873 fChain, err := follower.NewChain( 874 ledgerRes, 875 clusterConsenter, 876 joinBlock, 877 follower.Options{ 878 Logger: fLog, 879 }, 880 blockPullerCreator, 881 r, 882 r.bccsp, 883 r, 884 ) 885 if err != nil { 886 return nil, types.ChannelInfo{}, errors.WithMessagef(err, "failed to create follower for channel %s", channelID) 887 } 888 889 clusterRelation, status := fChain.StatusReport() 890 info := types.ChannelInfo{ 891 Name: channelID, 892 URL: "", 893 Height: ledgerRes.Height(), 894 ConsensusRelation: clusterRelation, 895 Status: status, 896 } 897 898 r.followers[channelID] = fChain 899 900 logger.Debugf("Created follower.Chain: %v", info) 901 return fChain, info, nil 902 } 903 904 // Assumes the system channel join-block is saved to the file repo. 905 func (r *Registrar) joinSystemChannel( 906 ledgerRes *ledgerResources, 907 clusterConsenter consensus.ClusterConsenter, 908 configBlock *cb.Block, 909 channelID string, 910 ) (types.ChannelInfo, error) { 911 logger.Infof("Joining system channel '%s', with config block number: %d", channelID, configBlock.Header.Number) 912 913 if configBlock.Header.Number == 0 { 914 if err := ledgerRes.Append(configBlock); err != nil { 915 return types.ChannelInfo{}, errors.WithMessage(err, "error appending config block to the ledger") 916 } 917 } 918 919 // This is a degenerate ChainSupport holding an inactive.Chain, that will respond to a GET request with the info 920 // returned below. This is an indication to the user/admin that the orderer needs a restart, and prevent 921 // conflicting channel participation API actions on the orderer. 922 cs, err := newOnBoardingChainSupport(ledgerRes, r.config, r.bccsp) 923 if err != nil { 924 return types.ChannelInfo{}, errors.WithMessage(err, "error creating onboarding chain support") 925 } 926 r.chains[channelID] = cs 927 r.systemChannel = cs 928 r.systemChannelID = channelID 929 930 info := types.ChannelInfo{ 931 Name: channelID, 932 URL: "", 933 Height: ledgerRes.Height(), 934 } 935 info.ConsensusRelation, info.Status = r.systemChannel.StatusReport() 936 937 logger.Infof("System channel creation pending: server requires restart! ChannelInfo: %v", info) 938 939 return info, nil 940 } 941 942 // RemoveChannel instructs the orderer to remove a channel. 943 func (r *Registrar) RemoveChannel(channelID string) error { 944 r.lock.Lock() 945 defer r.lock.Unlock() 946 947 status, ok := r.pendingRemoval[channelID] 948 if ok && status.Status != types.StatusFailed { 949 return types.ErrChannelPendingRemoval 950 } 951 952 if r.systemChannelID != "" { 953 if channelID != r.systemChannelID { 954 return types.ErrSystemChannelExists 955 } 956 return r.removeSystemChannel() 957 } 958 959 cs, ok := r.chains[channelID] 960 if ok { 961 cs.Halt() 962 r.removeMember(channelID, cs) 963 return nil 964 } 965 966 fChain, ok := r.followers[channelID] 967 if ok { 968 fChain.Halt() 969 return r.removeFollower(channelID, fChain) 970 } 971 972 return types.ErrChannelNotExist 973 } 974 975 func (r *Registrar) removeMember(channelID string, cs *ChainSupport) { 976 relation, status := cs.StatusReport() 977 r.pendingRemoval[channelID] = consensus.StaticStatusReporter{ConsensusRelation: relation, Status: status} 978 r.removeLedgerAsync(channelID) 979 980 delete(r.chains, channelID) 981 982 logger.Infof("Removed channel: %s", channelID) 983 } 984 985 func (r *Registrar) removeFollower(channelID string, follower *follower.Chain) error { 986 // join block may still exist if the follower is: 987 // 1) still onboarding 988 // 2) active but not yet called registrar.SwitchFollowerToChain() 989 // NOTE: if the join block does not exist, os.RemoveAll returns nil 990 // so there is no harm attempting to remove a non-existent join block. 991 if err := r.removeJoinBlock(channelID); err != nil { 992 return err 993 } 994 995 relation, status := follower.StatusReport() 996 r.pendingRemoval[channelID] = consensus.StaticStatusReporter{ConsensusRelation: relation, Status: status} 997 r.removeLedgerAsync(channelID) 998 999 delete(r.followers, channelID) 1000 1001 logger.Infof("Removed channel: %s", channelID) 1002 1003 return nil 1004 } 1005 1006 func (r *Registrar) loadJoinBlocks() map[string]*cb.Block { 1007 channelToBlockMap := make(map[string]*cb.Block) 1008 if !r.config.ChannelParticipation.Enabled { 1009 return channelToBlockMap 1010 } 1011 channelsList, err := r.joinBlockFileRepo.List() 1012 if err != nil { 1013 logger.Panicf("Error listing join block file repo: %s", err) 1014 } 1015 1016 logger.Debugf("Loading join-blocks for %d channels: %s", len(channelsList), channelsList) 1017 for _, fileName := range channelsList { 1018 channelName := r.joinBlockFileRepo.FileToBaseName(fileName) 1019 blockBytes, err := r.joinBlockFileRepo.Read(channelName) 1020 if err != nil { 1021 logger.Panicf("Error reading join block file: '%s', error: %s", fileName, err) 1022 } 1023 block, err := protoutil.UnmarshalBlock(blockBytes) 1024 if err != nil { 1025 logger.Panicf("Error unmarshalling join block file: '%s', error: %s", fileName, err) 1026 } 1027 channelToBlockMap[channelName] = block 1028 } 1029 1030 logger.Debug("Reconciling join-blocks and ledger by creating any missing ledger") 1031 for channelID := range channelToBlockMap { 1032 if _, err := r.ledgerFactory.GetOrCreate(channelID); err != nil { 1033 logger.Panicf("Failed to create a ledger for channel: '%s', error: %s", channelID, err) 1034 } 1035 } 1036 1037 return channelToBlockMap 1038 } 1039 1040 func (r *Registrar) removeJoinBlock(channelID string) error { 1041 if err := r.joinBlockFileRepo.Remove(channelID); err != nil { 1042 return errors.WithMessagef(err, "failed removing joinblock for channel %s", channelID) 1043 } 1044 1045 return nil 1046 } 1047 1048 func (r *Registrar) removeSystemChannel() error { 1049 systemChannelID := r.systemChannelID 1050 consensusType := r.systemChannel.SharedConfig().ConsensusType() 1051 if consensusType != "etcdraft" { 1052 return errors.Errorf("cannot remove %s system channel: %s", consensusType, systemChannelID) 1053 } 1054 1055 // halt the inactive chain registry 1056 consenter := r.consenters["etcdraft"].(consensus.ClusterConsenter) 1057 consenter.RemoveInactiveChainRegistry() 1058 1059 // halt the system channel and remove it from the chains map 1060 r.systemChannel.Halt() 1061 delete(r.chains, systemChannelID) 1062 1063 // remove system channel resources 1064 err := r.ledgerFactory.Remove(systemChannelID) 1065 if err != nil { 1066 return errors.WithMessagef(err, "failed removing ledger for system channel %s", r.systemChannelID) 1067 } 1068 1069 // remove system channel references 1070 r.systemChannel = nil 1071 r.systemChannelID = "" 1072 logger.Infof("removed system channel: %s", systemChannelID) 1073 1074 failedRemovals := []string{} 1075 1076 // halt all application channels 1077 for channel, cs := range r.chains { 1078 cs.Halt() 1079 1080 rl, err := r.ledgerFactory.GetOrCreate(channel) 1081 if err != nil { 1082 return errors.WithMessagef(err, "could not retrieve ledger for channel: %s", channel) 1083 } 1084 configBlock := ConfigBlockOrPanic(rl) 1085 isChannelMember, err := consenter.IsChannelMember(configBlock) 1086 if err != nil { 1087 return errors.WithMessagef(err, "failed to determine channel membership for channel: %s", channel) 1088 } 1089 if !isChannelMember { 1090 logger.Debugf("not a member of channel %s, removing it", channel) 1091 err := r.ledgerFactory.Remove(channel) 1092 if err != nil { 1093 logger.Errorf("failed removing ledger for channel %s, error: %v", channel, err) 1094 failedRemovals = append(failedRemovals, channel) 1095 continue 1096 } 1097 1098 delete(r.chains, channel) 1099 } 1100 } 1101 1102 if len(failedRemovals) > 0 { 1103 return fmt.Errorf("failed removing ledger for channel(s): %s", strings.Join(failedRemovals, ", ")) 1104 } 1105 1106 // reintialize the registrar to recreate every channel 1107 r.init(r.consenters) 1108 1109 // restart every channel 1110 r.startChannels() 1111 1112 return nil 1113 } 1114 1115 func (r *Registrar) removeLedgerAsync(channelID string) { 1116 go func() { 1117 err := r.ledgerFactory.Remove(channelID) 1118 r.lock.Lock() 1119 defer r.lock.Unlock() 1120 if err != nil { 1121 r.pendingRemoval[channelID] = consensus.StaticStatusReporter{ConsensusRelation: r.pendingRemoval[channelID].ConsensusRelation, Status: types.StatusFailed} 1122 r.channelParticipationMetrics.reportStatus(channelID, types.StatusFailed) 1123 logger.Errorf("ledger factory failed to remove empty ledger '%s', error: %s", channelID, err) 1124 return 1125 } 1126 delete(r.pendingRemoval, channelID) 1127 }() 1128 } 1129 1130 func (r *Registrar) ReportConsensusRelationAndStatusMetrics(channelID string, relation types.ConsensusRelation, status types.Status) { 1131 r.channelParticipationMetrics.reportConsensusRelation(channelID, relation) 1132 r.channelParticipationMetrics.reportStatus(channelID, status) 1133 } 1134 1135 func channelNameFromConfigTx(configtx *cb.Envelope) (string, error) { 1136 payload, err := protoutil.UnmarshalPayload(configtx.Payload) 1137 if err != nil { 1138 return "", errors.WithMessage(err, "error umarshaling envelope to payload") 1139 } 1140 1141 if payload.Header == nil { 1142 return "", errors.New("missing channel header") 1143 } 1144 1145 chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader) 1146 if err != nil { 1147 return "", errors.WithMessage(err, "error unmarshalling channel header") 1148 } 1149 1150 return chdr.ChannelId, nil 1151 }