github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/orderer/multichain/manager.go (about)

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