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  }