github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/orderer/multichain/manager.go (about)

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