github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/orderer/common/multichannel/manager.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  
    15  	"github.com/hyperledger/fabric/common/config"
    16  	"github.com/hyperledger/fabric/common/configtx"
    17  	configtxapi "github.com/hyperledger/fabric/common/configtx/api"
    18  	"github.com/hyperledger/fabric/common/policies"
    19  	"github.com/hyperledger/fabric/orderer/common/ledger"
    20  	cb "github.com/hyperledger/fabric/protos/common"
    21  	"github.com/hyperledger/fabric/protos/utils"
    22  	"github.com/op/go-logging"
    23  
    24  	"github.com/golang/protobuf/proto"
    25  	"github.com/hyperledger/fabric/common/crypto"
    26  )
    27  
    28  var logger = logging.MustGetLogger("orderer/multichannel")
    29  
    30  const (
    31  	msgVersion = int32(0)
    32  	epoch      = 0
    33  )
    34  
    35  // Manager coordinates the creation and access of chains
    36  type Manager interface {
    37  	// GetChain retrieves the chain support for a chain (and whether it exists)
    38  	GetChain(chainID string) (ChainSupport, bool)
    39  
    40  	// SystemChannelID returns the channel ID for the system channel
    41  	SystemChannelID() string
    42  
    43  	// NewChannelConfig returns a bare bones configuration ready for channel
    44  	// creation request to be applied on top of it
    45  	NewChannelConfig(envConfigUpdate *cb.Envelope) (configtxapi.Manager, error)
    46  }
    47  
    48  type configResources struct {
    49  	configtxapi.Manager
    50  }
    51  
    52  func (cr *configResources) SharedConfig() config.Orderer {
    53  	oc, ok := cr.OrdererConfig()
    54  	if !ok {
    55  		logger.Panicf("[channel %s] has no orderer configuration", cr.ChainID())
    56  	}
    57  	return oc
    58  }
    59  
    60  type ledgerResources struct {
    61  	*configResources
    62  	ledger ledger.ReadWriter
    63  }
    64  
    65  type multiLedger struct {
    66  	chains          map[string]*chainSupport
    67  	consenters      map[string]Consenter
    68  	ledgerFactory   ledger.Factory
    69  	signer          crypto.LocalSigner
    70  	systemChannelID string
    71  	systemChannel   *chainSupport
    72  }
    73  
    74  func getConfigTx(reader ledger.Reader) *cb.Envelope {
    75  	lastBlock := ledger.GetBlock(reader, reader.Height()-1)
    76  	index, err := utils.GetLastConfigIndexFromBlock(lastBlock)
    77  	if err != nil {
    78  		logger.Panicf("Chain did not have appropriately encoded last config in its latest block: %s", err)
    79  	}
    80  	configBlock := ledger.GetBlock(reader, index)
    81  	if configBlock == nil {
    82  		logger.Panicf("Config block does not exist")
    83  	}
    84  
    85  	return utils.ExtractEnvelopeOrPanic(configBlock, 0)
    86  }
    87  
    88  // NewManagerImpl produces an instance of a Manager
    89  func NewManagerImpl(ledgerFactory ledger.Factory, consenters map[string]Consenter, signer crypto.LocalSigner) Manager {
    90  	ml := &multiLedger{
    91  		chains:        make(map[string]*chainSupport),
    92  		ledgerFactory: ledgerFactory,
    93  		consenters:    consenters,
    94  		signer:        signer,
    95  	}
    96  
    97  	existingChains := ledgerFactory.ChainIDs()
    98  	for _, chainID := range existingChains {
    99  		rl, err := ledgerFactory.GetOrCreate(chainID)
   100  		if err != nil {
   101  			logger.Panicf("Ledger factory reported chainID %s but could not retrieve it: %s", chainID, err)
   102  		}
   103  		configTx := getConfigTx(rl)
   104  		if configTx == nil {
   105  			logger.Panic("Programming error, configTx should never be nil here")
   106  		}
   107  		ledgerResources := ml.newLedgerResources(configTx)
   108  		chainID := ledgerResources.ChainID()
   109  
   110  		if _, ok := ledgerResources.ConsortiumsConfig(); ok {
   111  			if ml.systemChannelID != "" {
   112  				logger.Panicf("There appear to be two system chains %s and %s", ml.systemChannelID, chainID)
   113  			}
   114  			chain := newChainSupport(createSystemChainFilters(ml, ledgerResources),
   115  				ledgerResources,
   116  				consenters,
   117  				signer)
   118  			logger.Infof("Starting with system channel %s and orderer type %s", chainID, chain.SharedConfig().ConsensusType())
   119  			ml.chains[chainID] = chain
   120  			ml.systemChannelID = chainID
   121  			ml.systemChannel = chain
   122  			// We delay starting this chain, as it might try to copy and replace the chains map via newChain before the map is fully built
   123  			defer chain.start()
   124  		} else {
   125  			logger.Debugf("Starting chain: %s", chainID)
   126  			chain := newChainSupport(createStandardFilters(ledgerResources),
   127  				ledgerResources,
   128  				consenters,
   129  				signer)
   130  			ml.chains[chainID] = chain
   131  			chain.start()
   132  		}
   133  
   134  	}
   135  
   136  	if ml.systemChannelID == "" {
   137  		logger.Panicf("No system chain found.  If bootstrapping, does your system channel contain a consortiums group definition?")
   138  	}
   139  
   140  	return ml
   141  }
   142  
   143  func (ml *multiLedger) SystemChannelID() string {
   144  	return ml.systemChannelID
   145  }
   146  
   147  // GetChain retrieves the chain support for a chain (and whether it exists)
   148  func (ml *multiLedger) GetChain(chainID string) (ChainSupport, bool) {
   149  	cs, ok := ml.chains[chainID]
   150  	return cs, ok
   151  }
   152  
   153  func (ml *multiLedger) newLedgerResources(configTx *cb.Envelope) *ledgerResources {
   154  	initializer := configtx.NewInitializer()
   155  	configManager, err := configtx.NewManagerImpl(configTx, initializer, nil)
   156  	if err != nil {
   157  		logger.Panicf("Error creating configtx manager and handlers: %s", err)
   158  	}
   159  
   160  	chainID := configManager.ChainID()
   161  
   162  	ledger, err := ml.ledgerFactory.GetOrCreate(chainID)
   163  	if err != nil {
   164  		logger.Panicf("Error getting ledger for %s", chainID)
   165  	}
   166  
   167  	return &ledgerResources{
   168  		configResources: &configResources{Manager: configManager},
   169  		ledger:          ledger,
   170  	}
   171  }
   172  
   173  func (ml *multiLedger) newChain(configtx *cb.Envelope) {
   174  	ledgerResources := ml.newLedgerResources(configtx)
   175  	ledgerResources.ledger.Append(ledger.CreateNextBlock(ledgerResources.ledger, []*cb.Envelope{configtx}))
   176  
   177  	// Copy the map to allow concurrent reads from broadcast/deliver while the new chainSupport is
   178  	newChains := make(map[string]*chainSupport)
   179  	for key, value := range ml.chains {
   180  		newChains[key] = value
   181  	}
   182  
   183  	cs := newChainSupport(createStandardFilters(ledgerResources), ledgerResources, ml.consenters, ml.signer)
   184  	chainID := ledgerResources.ChainID()
   185  
   186  	logger.Infof("Created and starting new chain %s", chainID)
   187  
   188  	newChains[string(chainID)] = cs
   189  	cs.start()
   190  
   191  	ml.chains = newChains
   192  }
   193  
   194  func (ml *multiLedger) channelsCount() int {
   195  	return len(ml.chains)
   196  }
   197  
   198  func (ml *multiLedger) NewChannelConfig(envConfigUpdate *cb.Envelope) (configtxapi.Manager, error) {
   199  	configUpdatePayload, err := utils.UnmarshalPayload(envConfigUpdate.Payload)
   200  	if err != nil {
   201  		return nil, fmt.Errorf("Failing initial channel config creation because of payload unmarshaling error: %s", err)
   202  	}
   203  
   204  	configUpdateEnv, err := configtx.UnmarshalConfigUpdateEnvelope(configUpdatePayload.Data)
   205  	if err != nil {
   206  		return nil, fmt.Errorf("Failing initial channel config creation because of config update envelope unmarshaling error: %s", err)
   207  	}
   208  
   209  	if configUpdatePayload.Header == nil {
   210  		return nil, fmt.Errorf("Failed initial channel config creation because config update header was missing")
   211  	}
   212  	channelHeader, err := utils.UnmarshalChannelHeader(configUpdatePayload.Header.ChannelHeader)
   213  
   214  	configUpdate, err := configtx.UnmarshalConfigUpdate(configUpdateEnv.ConfigUpdate)
   215  	if err != nil {
   216  		return nil, fmt.Errorf("Failing initial channel config creation because of config update unmarshaling error: %s", err)
   217  	}
   218  
   219  	if configUpdate.ChannelId != channelHeader.ChannelId {
   220  		return nil, fmt.Errorf("Failing initial channel config creation: mismatched channel IDs: '%s' != '%s'", configUpdate.ChannelId, channelHeader.ChannelId)
   221  	}
   222  
   223  	if configUpdate.WriteSet == nil {
   224  		return nil, fmt.Errorf("Config update has an empty writeset")
   225  	}
   226  
   227  	if configUpdate.WriteSet.Groups == nil || configUpdate.WriteSet.Groups[config.ApplicationGroupKey] == nil {
   228  		return nil, fmt.Errorf("Config update has missing application group")
   229  	}
   230  
   231  	if uv := configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Version; uv != 1 {
   232  		return nil, fmt.Errorf("Config update for channel creation does not set application group version to 1, was %d", uv)
   233  	}
   234  
   235  	consortiumConfigValue, ok := configUpdate.WriteSet.Values[config.ConsortiumKey]
   236  	if !ok {
   237  		return nil, fmt.Errorf("Consortium config value missing")
   238  	}
   239  
   240  	consortium := &cb.Consortium{}
   241  	err = proto.Unmarshal(consortiumConfigValue.Value, consortium)
   242  	if err != nil {
   243  		return nil, fmt.Errorf("Error reading unmarshaling consortium name: %s", err)
   244  	}
   245  
   246  	applicationGroup := cb.NewConfigGroup()
   247  	consortiumsConfig, ok := ml.systemChannel.ConsortiumsConfig()
   248  	if !ok {
   249  		return nil, fmt.Errorf("The ordering system channel does not appear to support creating channels")
   250  	}
   251  
   252  	consortiumConf, ok := consortiumsConfig.Consortiums()[consortium.Name]
   253  	if !ok {
   254  		return nil, fmt.Errorf("Unknown consortium name: %s", consortium.Name)
   255  	}
   256  
   257  	applicationGroup.Policies[config.ChannelCreationPolicyKey] = &cb.ConfigPolicy{
   258  		Policy: consortiumConf.ChannelCreationPolicy(),
   259  	}
   260  	applicationGroup.ModPolicy = config.ChannelCreationPolicyKey
   261  
   262  	// Get the current system channel config
   263  	systemChannelGroup := ml.systemChannel.ConfigEnvelope().Config.ChannelGroup
   264  
   265  	// If the consortium group has no members, allow the source request to have no members.  However,
   266  	// if the consortium group has any members, there must be at least one member in the source request
   267  	if len(systemChannelGroup.Groups[config.ConsortiumsGroupKey].Groups[consortium.Name].Groups) > 0 &&
   268  		len(configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups) == 0 {
   269  		return nil, fmt.Errorf("Proposed configuration has no application group members, but consortium contains members")
   270  	}
   271  
   272  	// If the consortium has no members, allow the source request to contain arbitrary members
   273  	// Otherwise, require that the supplied members are a subset of the consortium members
   274  	if len(systemChannelGroup.Groups[config.ConsortiumsGroupKey].Groups[consortium.Name].Groups) > 0 {
   275  		for orgName := range configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups {
   276  			consortiumGroup, ok := systemChannelGroup.Groups[config.ConsortiumsGroupKey].Groups[consortium.Name].Groups[orgName]
   277  			if !ok {
   278  				return nil, fmt.Errorf("Attempted to include a member which is not in the consortium")
   279  			}
   280  			applicationGroup.Groups[orgName] = consortiumGroup
   281  		}
   282  	}
   283  
   284  	channelGroup := cb.NewConfigGroup()
   285  
   286  	// Copy the system channel Channel level config to the new config
   287  	for key, value := range systemChannelGroup.Values {
   288  		channelGroup.Values[key] = value
   289  		if key == config.ConsortiumKey {
   290  			// Do not set the consortium name, we do this later
   291  			continue
   292  		}
   293  	}
   294  
   295  	for key, policy := range systemChannelGroup.Policies {
   296  		channelGroup.Policies[key] = policy
   297  	}
   298  
   299  	// Set the new config orderer group to the system channel orderer group and the application group to the new application group
   300  	channelGroup.Groups[config.OrdererGroupKey] = systemChannelGroup.Groups[config.OrdererGroupKey]
   301  	channelGroup.Groups[config.ApplicationGroupKey] = applicationGroup
   302  	channelGroup.Values[config.ConsortiumKey] = config.TemplateConsortium(consortium.Name).Values[config.ConsortiumKey]
   303  
   304  	templateConfig, _ := utils.CreateSignedEnvelope(cb.HeaderType_CONFIG, configUpdate.ChannelId, ml.signer, &cb.ConfigEnvelope{
   305  		Config: &cb.Config{
   306  			ChannelGroup: channelGroup,
   307  		},
   308  	}, msgVersion, epoch)
   309  
   310  	initializer := configtx.NewInitializer()
   311  
   312  	// This is a very hacky way to disable the sanity check logging in the policy manager
   313  	// for the template configuration, but it is the least invasive near a release
   314  	pm, ok := initializer.PolicyManager().(*policies.ManagerImpl)
   315  	if ok {
   316  		pm.SuppressSanityLogMessages = true
   317  		defer func() {
   318  			pm.SuppressSanityLogMessages = false
   319  		}()
   320  	}
   321  
   322  	return configtx.NewManagerImpl(templateConfig, initializer, nil)
   323  }