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