github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/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/osdi23p228/fabric/bccsp"
    19  	"github.com/osdi23p228/fabric/common/channelconfig"
    20  	"github.com/osdi23p228/fabric/common/configtx"
    21  	"github.com/osdi23p228/fabric/common/flogging"
    22  	"github.com/osdi23p228/fabric/common/ledger/blockledger"
    23  	"github.com/osdi23p228/fabric/common/metrics"
    24  	"github.com/osdi23p228/fabric/internal/pkg/identity"
    25  	"github.com/osdi23p228/fabric/orderer/common/blockcutter"
    26  	"github.com/osdi23p228/fabric/orderer/common/localconfig"
    27  	"github.com/osdi23p228/fabric/orderer/common/msgprocessor"
    28  	"github.com/osdi23p228/fabric/orderer/common/types"
    29  	"github.com/osdi23p228/fabric/orderer/consensus"
    30  	"github.com/osdi23p228/fabric/protoutil"
    31  	"github.com/pkg/errors"
    32  )
    33  
    34  const (
    35  	msgVersion = int32(0)
    36  	epoch      = 0
    37  )
    38  
    39  var logger = flogging.MustGetLogger("orderer.commmon.multichannel")
    40  
    41  // checkResources makes sure that the channel config is compatible with this binary and logs sanity checks
    42  func checkResources(res channelconfig.Resources) error {
    43  	channelconfig.LogSanityChecks(res)
    44  	oc, ok := res.OrdererConfig()
    45  	if !ok {
    46  		return errors.New("config does not contain orderer config")
    47  	}
    48  	if err := oc.Capabilities().Supported(); err != nil {
    49  		return errors.Wrapf(err, "config requires unsupported orderer capabilities: %s", err)
    50  	}
    51  	if err := res.ChannelConfig().Capabilities().Supported(); err != nil {
    52  		return errors.Wrapf(err, "config requires unsupported channel capabilities: %s", err)
    53  	}
    54  	return nil
    55  }
    56  
    57  // checkResourcesOrPanic invokes checkResources and panics if an error is returned
    58  func checkResourcesOrPanic(res channelconfig.Resources) {
    59  	if err := checkResources(res); err != nil {
    60  		logger.Panicf("[channel %s] %s", res.ConfigtxValidator().ChannelID(), err)
    61  	}
    62  }
    63  
    64  type mutableResources interface {
    65  	channelconfig.Resources
    66  	Update(*channelconfig.Bundle)
    67  }
    68  
    69  type configResources struct {
    70  	mutableResources
    71  	bccsp bccsp.BCCSP
    72  }
    73  
    74  func (cr *configResources) CreateBundle(channelID string, config *cb.Config) (*channelconfig.Bundle, error) {
    75  	return channelconfig.NewBundle(channelID, config, cr.bccsp)
    76  }
    77  
    78  func (cr *configResources) Update(bndl *channelconfig.Bundle) {
    79  	checkResourcesOrPanic(bndl)
    80  	cr.mutableResources.Update(bndl)
    81  }
    82  
    83  func (cr *configResources) SharedConfig() channelconfig.Orderer {
    84  	oc, ok := cr.OrdererConfig()
    85  	if !ok {
    86  		logger.Panicf("[channel %s] has no orderer configuration", cr.ConfigtxValidator().ChannelID())
    87  	}
    88  	return oc
    89  }
    90  
    91  type ledgerResources struct {
    92  	*configResources
    93  	blockledger.ReadWriter
    94  }
    95  
    96  // Registrar serves as a point of access and control for the individual channel resources.
    97  type Registrar struct {
    98  	config localconfig.TopLevel
    99  	lock   sync.RWMutex
   100  	chains map[string]*ChainSupport
   101  
   102  	consenters         map[string]consensus.Consenter
   103  	ledgerFactory      blockledger.Factory
   104  	signer             identity.SignerSerializer
   105  	blockcutterMetrics *blockcutter.Metrics
   106  	systemChannelID    string
   107  	systemChannel      *ChainSupport
   108  	templator          msgprocessor.ChannelConfigTemplator
   109  	callbacks          []channelconfig.BundleActor
   110  	bccsp              bccsp.BCCSP
   111  }
   112  
   113  // ConfigBlock retrieves the last configuration block from the given ledger.
   114  // Panics on failure.
   115  func ConfigBlock(reader blockledger.Reader) *cb.Block {
   116  	lastBlock := blockledger.GetBlock(reader, reader.Height()-1)
   117  	index, err := protoutil.GetLastConfigIndexFromBlock(lastBlock)
   118  	if err != nil {
   119  		logger.Panicf("Chain did not have appropriately encoded last config in its latest block: %s", err)
   120  	}
   121  	configBlock := blockledger.GetBlock(reader, index)
   122  	if configBlock == nil {
   123  		logger.Panicf("Config block does not exist")
   124  	}
   125  
   126  	return configBlock
   127  }
   128  
   129  func configTx(reader blockledger.Reader) *cb.Envelope {
   130  	return protoutil.ExtractEnvelopeOrPanic(ConfigBlock(reader), 0)
   131  }
   132  
   133  // NewRegistrar produces an instance of a *Registrar.
   134  func NewRegistrar(
   135  	config localconfig.TopLevel,
   136  	ledgerFactory blockledger.Factory,
   137  	signer identity.SignerSerializer,
   138  	metricsProvider metrics.Provider,
   139  	bccsp bccsp.BCCSP,
   140  	callbacks ...channelconfig.BundleActor,
   141  ) *Registrar {
   142  	r := &Registrar{
   143  		config:             config,
   144  		chains:             make(map[string]*ChainSupport),
   145  		ledgerFactory:      ledgerFactory,
   146  		signer:             signer,
   147  		blockcutterMetrics: blockcutter.NewMetrics(metricsProvider),
   148  		callbacks:          callbacks,
   149  		bccsp:              bccsp,
   150  	}
   151  
   152  	return r
   153  }
   154  
   155  func (r *Registrar) Initialize(consenters map[string]consensus.Consenter) {
   156  	r.consenters = consenters
   157  	existingChannels := r.ledgerFactory.ChannelIDs()
   158  
   159  	for _, channelID := range existingChannels {
   160  		rl, err := r.ledgerFactory.GetOrCreate(channelID)
   161  		if err != nil {
   162  			logger.Panicf("Ledger factory reported channelID %s but could not retrieve it: %s", channelID, err)
   163  		}
   164  		configTx := configTx(rl)
   165  		if configTx == nil {
   166  			logger.Panic("Programming error, configTx should never be nil here")
   167  		}
   168  		ledgerResources, err := r.newLedgerResources(configTx)
   169  		if err != nil {
   170  			logger.Panicf("Error creating ledger resources: %s", err)
   171  		}
   172  		channelID := ledgerResources.ConfigtxValidator().ChannelID()
   173  
   174  		if _, ok := ledgerResources.ConsortiumsConfig(); ok {
   175  			if r.systemChannelID != "" {
   176  				logger.Panicf("There appear to be two system channels %s and %s", r.systemChannelID, channelID)
   177  			}
   178  
   179  			chain, err := newChainSupport(
   180  				r,
   181  				ledgerResources,
   182  				r.consenters,
   183  				r.signer,
   184  				r.blockcutterMetrics,
   185  				r.bccsp,
   186  			)
   187  			if err != nil {
   188  				logger.Panicf("Error creating chain support: %s", err)
   189  			}
   190  			r.templator = msgprocessor.NewDefaultTemplator(chain, r.bccsp)
   191  			chain.Processor = msgprocessor.NewSystemChannel(
   192  				chain,
   193  				r.templator,
   194  				msgprocessor.CreateSystemChannelFilters(r.config, r, chain, chain.MetadataValidator),
   195  				r.bccsp,
   196  			)
   197  
   198  			// Retrieve genesis block to log its hash. See FAB-5450 for the purpose
   199  			iter, pos := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Oldest{Oldest: &ab.SeekOldest{}}})
   200  			defer iter.Close()
   201  			if pos != uint64(0) {
   202  				logger.Panicf("Error iterating over system channel: '%s', expected position 0, got %d", channelID, pos)
   203  			}
   204  			genesisBlock, status := iter.Next()
   205  			if status != cb.Status_SUCCESS {
   206  				logger.Panicf("Error reading genesis block of system channel '%s'", channelID)
   207  			}
   208  			logger.Infof("Starting system channel '%s' with genesis block hash %x and orderer type %s",
   209  				channelID, protoutil.BlockHeaderHash(genesisBlock.Header), chain.SharedConfig().ConsensusType())
   210  
   211  			r.chains[channelID] = chain
   212  			r.systemChannelID = channelID
   213  			r.systemChannel = chain
   214  			// We delay starting this channel, as it might try to copy and replace the channels map via newChannel before the map is fully built
   215  			defer chain.start()
   216  		} else {
   217  			logger.Debugf("Starting channel: %s", channelID)
   218  			chain, err := newChainSupport(
   219  				r,
   220  				ledgerResources,
   221  				r.consenters,
   222  				r.signer,
   223  				r.blockcutterMetrics,
   224  				r.bccsp,
   225  			)
   226  			if err != nil {
   227  				logger.Panicf("Error creating chain support: %s", err)
   228  			}
   229  			r.chains[channelID] = chain
   230  			chain.start()
   231  		}
   232  	}
   233  
   234  	if r.systemChannelID == "" {
   235  		logger.Infof("Registrar initializing without a system channel, number of application channels: %d", len(r.chains))
   236  		if _, etcdRaftFound := r.consenters["etcdraft"]; !etcdRaftFound {
   237  			logger.Panicf("Error initializing without a system channel: failed to find an etcdraft consenter")
   238  		}
   239  	}
   240  }
   241  
   242  // SystemChannelID returns the ChannelID for the system channel.
   243  func (r *Registrar) SystemChannelID() string {
   244  	r.lock.RLock()
   245  	defer r.lock.RUnlock()
   246  	return r.systemChannelID
   247  }
   248  
   249  // SystemChannel returns the ChainSupport for the system channel.
   250  func (r *Registrar) SystemChannel() *ChainSupport {
   251  	r.lock.RLock()
   252  	defer r.lock.RUnlock()
   253  	return r.systemChannel
   254  }
   255  
   256  // BroadcastChannelSupport returns the message channel header, whether the message is a config update
   257  // and the channel resources for a message or an error if the message is not a message which can
   258  // be processed directly (like CONFIG and ORDERER_TRANSACTION messages)
   259  func (r *Registrar) BroadcastChannelSupport(msg *cb.Envelope) (*cb.ChannelHeader, bool, *ChainSupport, error) {
   260  	chdr, err := protoutil.ChannelHeader(msg)
   261  	if err != nil {
   262  		return nil, false, nil, fmt.Errorf("could not determine channel ID: %s", err)
   263  	}
   264  
   265  	cs := r.GetChain(chdr.ChannelId)
   266  	// New channel creation
   267  	if cs == nil {
   268  		sysChan := r.SystemChannel()
   269  		if sysChan == nil {
   270  			return nil, false, nil, errors.New("channel creation request not allowed because the orderer system channel is not defined")
   271  		}
   272  		cs = sysChan
   273  	}
   274  
   275  	isConfig := false
   276  	switch cs.ClassifyMsg(chdr) {
   277  	case msgprocessor.ConfigUpdateMsg:
   278  		isConfig = true
   279  	case msgprocessor.ConfigMsg:
   280  		return chdr, false, nil, errors.New("message is of type that cannot be processed directly")
   281  	default:
   282  	}
   283  
   284  	return chdr, isConfig, cs, nil
   285  }
   286  
   287  // GetChain retrieves the chain support for a chain if it exists.
   288  func (r *Registrar) GetChain(chainID string) *ChainSupport {
   289  	r.lock.RLock()
   290  	defer r.lock.RUnlock()
   291  
   292  	return r.chains[chainID]
   293  }
   294  
   295  func (r *Registrar) newLedgerResources(configTx *cb.Envelope) (*ledgerResources, error) {
   296  	payload, err := protoutil.UnmarshalPayload(configTx.Payload)
   297  	if err != nil {
   298  		return nil, errors.Wrap(err, "error umarshaling envelope to payload")
   299  	}
   300  
   301  	if payload.Header == nil {
   302  		return nil, errors.New("missing channel header")
   303  	}
   304  
   305  	chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   306  	if err != nil {
   307  		return nil, errors.Wrapf(err, "error unmarshaling channel header")
   308  	}
   309  
   310  	configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data)
   311  	if err != nil {
   312  		return nil, errors.Wrap(err, "error umarshaling config envelope from payload data")
   313  	}
   314  
   315  	bundle, err := channelconfig.NewBundle(chdr.ChannelId, configEnvelope.Config, r.bccsp)
   316  	if err != nil {
   317  		return nil, errors.Wrap(err, "error creating channelconfig bundle")
   318  	}
   319  
   320  	err = checkResources(bundle)
   321  	if err != nil {
   322  		return nil, errors.Wrapf(err, "error checking bundle for channel: %s", chdr.ChannelId)
   323  	}
   324  
   325  	ledger, err := r.ledgerFactory.GetOrCreate(chdr.ChannelId)
   326  	if err != nil {
   327  		return nil, errors.Wrapf(err, "error getting ledger for channel: %s", chdr.ChannelId)
   328  	}
   329  
   330  	return &ledgerResources{
   331  		configResources: &configResources{
   332  			mutableResources: channelconfig.NewBundleSource(bundle, r.callbacks...),
   333  			bccsp:            r.bccsp,
   334  		},
   335  		ReadWriter: ledger,
   336  	}, nil
   337  }
   338  
   339  // CreateChain makes the Registrar create a chain with the given name.
   340  func (r *Registrar) CreateChain(chainName string) {
   341  	lf, err := r.ledgerFactory.GetOrCreate(chainName)
   342  	if err != nil {
   343  		logger.Panicf("Failed obtaining ledger factory for %s: %v", chainName, err)
   344  	}
   345  	chain := r.GetChain(chainName)
   346  	if chain != nil {
   347  		logger.Infof("A chain of type %T for channel %s already exists. "+
   348  			"Halting it.", chain.Chain, chainName)
   349  		chain.Halt()
   350  	}
   351  	r.newChain(configTx(lf))
   352  }
   353  
   354  func (r *Registrar) newChain(configtx *cb.Envelope) {
   355  	r.lock.Lock()
   356  	defer r.lock.Unlock()
   357  
   358  	ledgerResources, err := r.newLedgerResources(configtx)
   359  	if err != nil {
   360  		logger.Panicf("Error creating ledger resources: %s", err)
   361  	}
   362  
   363  	// If we have no blocks, we need to create the genesis block ourselves.
   364  	if ledgerResources.Height() == 0 {
   365  		ledgerResources.Append(blockledger.CreateNextBlock(ledgerResources, []*cb.Envelope{configtx}))
   366  	}
   367  	cs, err := newChainSupport(r, ledgerResources, r.consenters, r.signer, r.blockcutterMetrics, r.bccsp)
   368  	if err != nil {
   369  		logger.Panicf("Error creating chain support: %s", err)
   370  	}
   371  
   372  	chainID := ledgerResources.ConfigtxValidator().ChannelID()
   373  	r.chains[chainID] = cs
   374  
   375  	logger.Infof("Created and starting new channel %s", chainID)
   376  	cs.start()
   377  }
   378  
   379  // ChannelsCount returns the count of the current total number of channels.
   380  func (r *Registrar) ChannelsCount() int {
   381  	r.lock.RLock()
   382  	defer r.lock.RUnlock()
   383  
   384  	return len(r.chains)
   385  }
   386  
   387  // NewChannelConfig produces a new template channel configuration based on the system channel's current config.
   388  func (r *Registrar) NewChannelConfig(envConfigUpdate *cb.Envelope) (channelconfig.Resources, error) {
   389  	return r.templator.NewChannelConfig(envConfigUpdate)
   390  }
   391  
   392  // CreateBundle calls channelconfig.NewBundle
   393  func (r *Registrar) CreateBundle(channelID string, config *cb.Config) (channelconfig.Resources, error) {
   394  	return channelconfig.NewBundle(channelID, config, r.bccsp)
   395  }
   396  
   397  // ChannelList returns a slice of ChannelInfoShort containing all application channels (excluding the system
   398  // channel), and ChannelInfoShort of the system channel (nil if does not exist).
   399  // The URL fields are empty, and are to be completed by the caller.
   400  func (r *Registrar) ChannelList() types.ChannelList {
   401  	r.lock.RLock()
   402  	defer r.lock.RUnlock()
   403  
   404  	list := types.ChannelList{}
   405  
   406  	if len(r.chains) == 0 {
   407  		return list
   408  	}
   409  
   410  	if r.systemChannelID != "" {
   411  		list.SystemChannel = &types.ChannelInfoShort{Name: r.systemChannelID}
   412  	}
   413  	for name := range r.chains {
   414  		if name == r.systemChannelID {
   415  			continue
   416  		}
   417  		list.Channels = append(list.Channels, types.ChannelInfoShort{Name: name})
   418  	}
   419  
   420  	return list
   421  }
   422  
   423  func (r *Registrar) ChannelInfo(channelID string) (types.ChannelInfo, error) {
   424  	r.lock.RLock()
   425  	defer r.lock.RUnlock()
   426  
   427  	info := types.ChannelInfo{}
   428  	cs, ok := r.chains[channelID]
   429  	if !ok {
   430  		return info, types.ErrChannelNotExist
   431  	}
   432  
   433  	info.Name = channelID
   434  	info.Height = cs.Height()
   435  	info.ClusterRelation, info.Status = cs.StatusReport()
   436  
   437  	return info, nil
   438  }
   439  
   440  func (r *Registrar) JoinChannel(channelID string, configBlock *cb.Block, isAppChannel bool) (types.ChannelInfo, error) {
   441  	r.lock.RLock()
   442  	defer r.lock.RUnlock()
   443  
   444  	if r.systemChannelID != "" {
   445  		return types.ChannelInfo{}, types.ErrSystemChannelExists
   446  	}
   447  
   448  	_, ok := r.chains[channelID]
   449  	if ok {
   450  		return types.ChannelInfo{}, types.ErrChannelAlreadyExists
   451  	}
   452  
   453  	if !isAppChannel && len(r.chains) > 0 {
   454  		return types.ChannelInfo{}, types.ErrAppChannelsAlreadyExists
   455  	}
   456  
   457  	configEnv, err := protoutil.ExtractEnvelope(configBlock, 0)
   458  	if err != nil {
   459  		return types.ChannelInfo{}, errors.Wrap(err, "failed extracting config envelope from block")
   460  	}
   461  
   462  	//TODO save the join-block in the file repo to make this action crash tolerant.
   463  
   464  	ledgerResources, err := r.newLedgerResources(configEnv)
   465  	if err != nil {
   466  		//TODO remove join block
   467  		return types.ChannelInfo{}, errors.Wrap(err, "failed creating ledger resources")
   468  	}
   469  
   470  	joinSupport, err := newChainSupportForJoin(configBlock, r, ledgerResources, r.consenters, r.signer, r.blockcutterMetrics, r.bccsp)
   471  	if err != nil {
   472  		//TODO remove join block, clean ledger resources
   473  		return types.ChannelInfo{}, errors.Wrap(err, "failed creating chain support for join")
   474  	}
   475  
   476  	info := types.ChannelInfo{
   477  		Name:   channelID,
   478  		URL:    "",
   479  		Height: ledgerResources.Height(),
   480  	}
   481  	info.ClusterRelation, info.Status = joinSupport.StatusReport()
   482  
   483  	logger.Infof("Joining new channel %s", channelID)
   484  
   485  	r.chains[channelID] = joinSupport
   486  	joinSupport.start()
   487  
   488  	return info, nil
   489  }
   490  
   491  func (r *Registrar) RemoveChannel(channelID string, removeStorage bool) error {
   492  	//TODO
   493  	return errors.New("Not implemented yet")
   494  }