github.com/anjalikarhana/fabric@v2.1.1+incompatible/orderer/common/multichannel/registrar.go (about)

     1  /*
     2  Copyright IBM Corp. 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  	"sync"
    15  
    16  	cb "github.com/hyperledger/fabric-protos-go/common"
    17  	ab "github.com/hyperledger/fabric-protos-go/orderer"
    18  	"github.com/hyperledger/fabric/bccsp"
    19  	"github.com/hyperledger/fabric/common/channelconfig"
    20  	"github.com/hyperledger/fabric/common/configtx"
    21  	"github.com/hyperledger/fabric/common/flogging"
    22  	"github.com/hyperledger/fabric/common/ledger/blockledger"
    23  	"github.com/hyperledger/fabric/common/metrics"
    24  	"github.com/hyperledger/fabric/internal/pkg/identity"
    25  	"github.com/hyperledger/fabric/orderer/common/blockcutter"
    26  	"github.com/hyperledger/fabric/orderer/common/localconfig"
    27  	"github.com/hyperledger/fabric/orderer/common/msgprocessor"
    28  	"github.com/hyperledger/fabric/orderer/consensus"
    29  	"github.com/hyperledger/fabric/protoutil"
    30  	"github.com/pkg/errors"
    31  )
    32  
    33  const (
    34  	msgVersion = int32(0)
    35  	epoch      = 0
    36  )
    37  
    38  var logger = flogging.MustGetLogger("orderer.commmon.multichannel")
    39  
    40  // checkResources makes sure that the channel config is compatible with this binary and logs sanity checks
    41  func checkResources(res channelconfig.Resources) error {
    42  	channelconfig.LogSanityChecks(res)
    43  	oc, ok := res.OrdererConfig()
    44  	if !ok {
    45  		return errors.New("config does not contain orderer config")
    46  	}
    47  	if err := oc.Capabilities().Supported(); err != nil {
    48  		return errors.Wrapf(err, "config requires unsupported orderer capabilities: %s", err)
    49  	}
    50  	if err := res.ChannelConfig().Capabilities().Supported(); err != nil {
    51  		return errors.Wrapf(err, "config requires unsupported channel capabilities: %s", err)
    52  	}
    53  	return nil
    54  }
    55  
    56  // checkResourcesOrPanic invokes checkResources and panics if an error is returned
    57  func checkResourcesOrPanic(res channelconfig.Resources) {
    58  	if err := checkResources(res); err != nil {
    59  		logger.Panicf("[channel %s] %s", res.ConfigtxValidator().ChannelID(), err)
    60  	}
    61  }
    62  
    63  type mutableResources interface {
    64  	channelconfig.Resources
    65  	Update(*channelconfig.Bundle)
    66  }
    67  
    68  type configResources struct {
    69  	mutableResources
    70  	bccsp bccsp.BCCSP
    71  }
    72  
    73  func (cr *configResources) CreateBundle(channelID string, config *cb.Config) (*channelconfig.Bundle, error) {
    74  	return channelconfig.NewBundle(channelID, config, cr.bccsp)
    75  }
    76  
    77  func (cr *configResources) Update(bndl *channelconfig.Bundle) {
    78  	checkResourcesOrPanic(bndl)
    79  	cr.mutableResources.Update(bndl)
    80  }
    81  
    82  func (cr *configResources) SharedConfig() channelconfig.Orderer {
    83  	oc, ok := cr.OrdererConfig()
    84  	if !ok {
    85  		logger.Panicf("[channel %s] has no orderer configuration", cr.ConfigtxValidator().ChannelID())
    86  	}
    87  	return oc
    88  }
    89  
    90  type ledgerResources struct {
    91  	*configResources
    92  	blockledger.ReadWriter
    93  }
    94  
    95  // Registrar serves as a point of access and control for the individual channel resources.
    96  type Registrar struct {
    97  	config localconfig.TopLevel
    98  	lock   sync.RWMutex
    99  	chains map[string]*ChainSupport
   100  
   101  	consenters         map[string]consensus.Consenter
   102  	ledgerFactory      blockledger.Factory
   103  	signer             identity.SignerSerializer
   104  	blockcutterMetrics *blockcutter.Metrics
   105  	systemChannelID    string
   106  	systemChannel      *ChainSupport
   107  	templator          msgprocessor.ChannelConfigTemplator
   108  	callbacks          []channelconfig.BundleActor
   109  	bccsp              bccsp.BCCSP
   110  }
   111  
   112  // ConfigBlock retrieves the last configuration block from the given ledger.
   113  // Panics on failure.
   114  func ConfigBlock(reader blockledger.Reader) *cb.Block {
   115  	lastBlock := blockledger.GetBlock(reader, reader.Height()-1)
   116  	index, err := protoutil.GetLastConfigIndexFromBlock(lastBlock)
   117  	if err != nil {
   118  		logger.Panicf("Chain did not have appropriately encoded last config in its latest block: %s", err)
   119  	}
   120  	configBlock := blockledger.GetBlock(reader, index)
   121  	if configBlock == nil {
   122  		logger.Panicf("Config block does not exist")
   123  	}
   124  
   125  	return configBlock
   126  }
   127  
   128  func configTx(reader blockledger.Reader) *cb.Envelope {
   129  	return protoutil.ExtractEnvelopeOrPanic(ConfigBlock(reader), 0)
   130  }
   131  
   132  // NewRegistrar produces an instance of a *Registrar.
   133  func NewRegistrar(
   134  	config localconfig.TopLevel,
   135  	ledgerFactory blockledger.Factory,
   136  	signer identity.SignerSerializer,
   137  	metricsProvider metrics.Provider,
   138  	bccsp bccsp.BCCSP,
   139  	callbacks ...channelconfig.BundleActor,
   140  ) *Registrar {
   141  	r := &Registrar{
   142  		config:             config,
   143  		chains:             make(map[string]*ChainSupport),
   144  		ledgerFactory:      ledgerFactory,
   145  		signer:             signer,
   146  		blockcutterMetrics: blockcutter.NewMetrics(metricsProvider),
   147  		callbacks:          callbacks,
   148  		bccsp:              bccsp,
   149  	}
   150  
   151  	return r
   152  }
   153  
   154  func (r *Registrar) Initialize(consenters map[string]consensus.Consenter) {
   155  	r.consenters = consenters
   156  	existingChannels := r.ledgerFactory.ChannelIDs()
   157  
   158  	for _, channelID := range existingChannels {
   159  		rl, err := r.ledgerFactory.GetOrCreate(channelID)
   160  		if err != nil {
   161  			logger.Panicf("Ledger factory reported channelID %s but could not retrieve it: %s", channelID, err)
   162  		}
   163  		configTx := configTx(rl)
   164  		if configTx == nil {
   165  			logger.Panic("Programming error, configTx should never be nil here")
   166  		}
   167  		ledgerResources := r.newLedgerResources(configTx)
   168  		channelID := ledgerResources.ConfigtxValidator().ChannelID()
   169  
   170  		if _, ok := ledgerResources.ConsortiumsConfig(); ok {
   171  			if r.systemChannelID != "" {
   172  				logger.Panicf("There appear to be two system channels %s and %s", r.systemChannelID, channelID)
   173  			}
   174  
   175  			chain := newChainSupport(
   176  				r,
   177  				ledgerResources,
   178  				r.consenters,
   179  				r.signer,
   180  				r.blockcutterMetrics,
   181  				r.bccsp,
   182  			)
   183  			r.templator = msgprocessor.NewDefaultTemplator(chain, r.bccsp)
   184  			chain.Processor = msgprocessor.NewSystemChannel(
   185  				chain,
   186  				r.templator,
   187  				msgprocessor.CreateSystemChannelFilters(r.config, r, chain, chain.MetadataValidator),
   188  				r.bccsp,
   189  			)
   190  
   191  			// Retrieve genesis block to log its hash. See FAB-5450 for the purpose
   192  			iter, pos := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Oldest{Oldest: &ab.SeekOldest{}}})
   193  			defer iter.Close()
   194  			if pos != uint64(0) {
   195  				logger.Panicf("Error iterating over system channel: '%s', expected position 0, got %d", channelID, pos)
   196  			}
   197  			genesisBlock, status := iter.Next()
   198  			if status != cb.Status_SUCCESS {
   199  				logger.Panicf("Error reading genesis block of system channel '%s'", channelID)
   200  			}
   201  			logger.Infof("Starting system channel '%s' with genesis block hash %x and orderer type %s",
   202  				channelID, protoutil.BlockHeaderHash(genesisBlock.Header), chain.SharedConfig().ConsensusType())
   203  
   204  			r.chains[channelID] = chain
   205  			r.systemChannelID = channelID
   206  			r.systemChannel = chain
   207  			// We delay starting this channel, as it might try to copy and replace the channels map via newChannel before the map is fully built
   208  			defer chain.start()
   209  		} else {
   210  			logger.Debugf("Starting channel: %s", channelID)
   211  			chain := newChainSupport(
   212  				r,
   213  				ledgerResources,
   214  				r.consenters,
   215  				r.signer,
   216  				r.blockcutterMetrics,
   217  				r.bccsp,
   218  			)
   219  			r.chains[channelID] = chain
   220  			chain.start()
   221  		}
   222  
   223  	}
   224  
   225  	if r.systemChannelID == "" {
   226  		logger.Warning("registrar initializing without a system channel")
   227  	}
   228  }
   229  
   230  // SystemChannelID returns the ChannelID for the system channel.
   231  func (r *Registrar) SystemChannelID() string {
   232  	return r.systemChannelID
   233  }
   234  
   235  // BroadcastChannelSupport returns the message channel header, whether the message is a config update
   236  // and the channel resources for a message or an error if the message is not a message which can
   237  // be processed directly (like CONFIG and ORDERER_TRANSACTION messages)
   238  func (r *Registrar) BroadcastChannelSupport(msg *cb.Envelope) (*cb.ChannelHeader, bool, *ChainSupport, error) {
   239  	chdr, err := protoutil.ChannelHeader(msg)
   240  	if err != nil {
   241  		return nil, false, nil, fmt.Errorf("could not determine channel ID: %s", err)
   242  	}
   243  
   244  	cs := r.GetChain(chdr.ChannelId)
   245  	// New channel creation
   246  	if cs == nil {
   247  		if r.systemChannel == nil {
   248  			return nil, false, nil, errors.New("channel creation request not allowed because the orderer system channel is not yet defined")
   249  		}
   250  		cs = r.systemChannel
   251  	}
   252  
   253  	isConfig := false
   254  	switch cs.ClassifyMsg(chdr) {
   255  	case msgprocessor.ConfigUpdateMsg:
   256  		isConfig = true
   257  	case msgprocessor.ConfigMsg:
   258  		return chdr, false, nil, errors.New("message is of type that cannot be processed directly")
   259  	default:
   260  	}
   261  
   262  	return chdr, isConfig, cs, nil
   263  }
   264  
   265  // GetChain retrieves the chain support for a chain if it exists.
   266  func (r *Registrar) GetChain(chainID string) *ChainSupport {
   267  	r.lock.RLock()
   268  	defer r.lock.RUnlock()
   269  
   270  	return r.chains[chainID]
   271  }
   272  
   273  func (r *Registrar) newLedgerResources(configTx *cb.Envelope) *ledgerResources {
   274  	payload, err := protoutil.UnmarshalPayload(configTx.Payload)
   275  	if err != nil {
   276  		logger.Panicf("Error umarshaling envelope to payload: %s", err)
   277  	}
   278  
   279  	if payload.Header == nil {
   280  		logger.Panicf("Missing channel header: %s", err)
   281  	}
   282  
   283  	chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   284  	if err != nil {
   285  		logger.Panicf("Error unmarshaling channel header: %s", err)
   286  	}
   287  
   288  	configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data)
   289  	if err != nil {
   290  		logger.Panicf("Error umarshaling config envelope from payload data: %s", err)
   291  	}
   292  
   293  	bundle, err := channelconfig.NewBundle(chdr.ChannelId, configEnvelope.Config, r.bccsp)
   294  	if err != nil {
   295  		logger.Panicf("Error creating channelconfig bundle: %s", err)
   296  	}
   297  
   298  	checkResourcesOrPanic(bundle)
   299  
   300  	ledger, err := r.ledgerFactory.GetOrCreate(chdr.ChannelId)
   301  	if err != nil {
   302  		logger.Panicf("Error getting ledger for %s", chdr.ChannelId)
   303  	}
   304  
   305  	return &ledgerResources{
   306  		configResources: &configResources{
   307  			mutableResources: channelconfig.NewBundleSource(bundle, r.callbacks...),
   308  			bccsp:            r.bccsp,
   309  		},
   310  		ReadWriter: ledger,
   311  	}
   312  }
   313  
   314  // CreateChain makes the Registrar create a chain with the given name.
   315  func (r *Registrar) CreateChain(chainName string) {
   316  	lf, err := r.ledgerFactory.GetOrCreate(chainName)
   317  	if err != nil {
   318  		logger.Panicf("Failed obtaining ledger factory for %s: %v", chainName, err)
   319  	}
   320  	chain := r.GetChain(chainName)
   321  	if chain != nil {
   322  		logger.Infof("A chain of type %T for channel %s already exists. "+
   323  			"Halting it.", chain.Chain, chainName)
   324  		chain.Halt()
   325  	}
   326  	r.newChain(configTx(lf))
   327  }
   328  
   329  func (r *Registrar) newChain(configtx *cb.Envelope) {
   330  	r.lock.Lock()
   331  	defer r.lock.Unlock()
   332  
   333  	ledgerResources := r.newLedgerResources(configtx)
   334  	// If we have no blocks, we need to create the genesis block ourselves.
   335  	if ledgerResources.Height() == 0 {
   336  		ledgerResources.Append(blockledger.CreateNextBlock(ledgerResources, []*cb.Envelope{configtx}))
   337  	}
   338  
   339  	// Copy the map to allow concurrent reads from broadcast/deliver while the new chainSupport is
   340  	newChains := make(map[string]*ChainSupport)
   341  	for key, value := range r.chains {
   342  		newChains[key] = value
   343  	}
   344  
   345  	cs := newChainSupport(r, ledgerResources, r.consenters, r.signer, r.blockcutterMetrics, r.bccsp)
   346  	chainID := ledgerResources.ConfigtxValidator().ChannelID()
   347  
   348  	logger.Infof("Created and starting new channel %s", chainID)
   349  
   350  	newChains[string(chainID)] = cs
   351  	cs.start()
   352  
   353  	r.chains = newChains
   354  }
   355  
   356  // ChannelsCount returns the count of the current total number of channels.
   357  func (r *Registrar) ChannelsCount() int {
   358  	r.lock.RLock()
   359  	defer r.lock.RUnlock()
   360  
   361  	return len(r.chains)
   362  }
   363  
   364  // NewChannelConfig produces a new template channel configuration based on the system channel's current config.
   365  func (r *Registrar) NewChannelConfig(envConfigUpdate *cb.Envelope) (channelconfig.Resources, error) {
   366  	return r.templator.NewChannelConfig(envConfigUpdate)
   367  }
   368  
   369  // CreateBundle calls channelconfig.NewBundle
   370  func (r *Registrar) CreateBundle(channelID string, config *cb.Config) (channelconfig.Resources, error) {
   371  	return channelconfig.NewBundle(channelID, config, r.bccsp)
   372  }