github.com/ewagmig/fabric@v2.1.1+incompatible/common/channelconfig/bundle.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package channelconfig
     8  
     9  import (
    10  	cb "github.com/hyperledger/fabric-protos-go/common"
    11  	"github.com/hyperledger/fabric/bccsp"
    12  	"github.com/hyperledger/fabric/common/cauthdsl"
    13  	"github.com/hyperledger/fabric/common/configtx"
    14  	"github.com/hyperledger/fabric/common/flogging"
    15  	"github.com/hyperledger/fabric/common/policies"
    16  	"github.com/hyperledger/fabric/msp"
    17  	"github.com/hyperledger/fabric/protoutil"
    18  	"github.com/pkg/errors"
    19  )
    20  
    21  var logger = flogging.MustGetLogger("common.channelconfig")
    22  
    23  // RootGroupKey is the key for namespacing the channel config, especially for
    24  // policy evaluation.
    25  const RootGroupKey = "Channel"
    26  
    27  // Bundle is a collection of resources which will always have a consistent
    28  // view of the channel configuration.  In particular, for a given bundle reference,
    29  // the config sequence, the policy manager etc. will always return exactly the
    30  // same value.  The Bundle structure is immutable and will always be replaced in its
    31  // entirety, with new backing memory.
    32  type Bundle struct {
    33  	policyManager   policies.Manager
    34  	channelConfig   *ChannelConfig
    35  	configtxManager configtx.Validator
    36  }
    37  
    38  // PolicyManager returns the policy manager constructed for this config.
    39  func (b *Bundle) PolicyManager() policies.Manager {
    40  	return b.policyManager
    41  }
    42  
    43  // MSPManager returns the MSP manager constructed for this config.
    44  func (b *Bundle) MSPManager() msp.MSPManager {
    45  	return b.channelConfig.MSPManager()
    46  }
    47  
    48  // ChannelConfig returns the config.Channel for the chain.
    49  func (b *Bundle) ChannelConfig() Channel {
    50  	return b.channelConfig
    51  }
    52  
    53  // OrdererConfig returns the config.Orderer for the channel
    54  // and whether the Orderer config exists.
    55  func (b *Bundle) OrdererConfig() (Orderer, bool) {
    56  	result := b.channelConfig.OrdererConfig()
    57  	return result, result != nil
    58  }
    59  
    60  // ConsortiumsConfig returns the config.Consortiums for the channel
    61  // and whether the consortiums config exists.
    62  func (b *Bundle) ConsortiumsConfig() (Consortiums, bool) {
    63  	result := b.channelConfig.ConsortiumsConfig()
    64  	return result, result != nil
    65  }
    66  
    67  // ApplicationConfig returns the configtxapplication.SharedConfig for the channel
    68  // and whether the Application config exists.
    69  func (b *Bundle) ApplicationConfig() (Application, bool) {
    70  	result := b.channelConfig.ApplicationConfig()
    71  	return result, result != nil
    72  }
    73  
    74  // ConfigtxValidator returns the configtx.Validator for the channel.
    75  func (b *Bundle) ConfigtxValidator() configtx.Validator {
    76  	return b.configtxManager
    77  }
    78  
    79  // ValidateNew checks if a new bundle's contained configuration is valid to be derived from the current bundle.
    80  // This allows checks of the nature "Make sure that the consensus type did not change".
    81  func (b *Bundle) ValidateNew(nb Resources) error {
    82  	if oc, ok := b.OrdererConfig(); ok {
    83  		noc, ok := nb.OrdererConfig()
    84  		if !ok {
    85  			return errors.New("current config has orderer section, but new config does not")
    86  		}
    87  
    88  		// Prevent consensus-type migration when channel capabilities ConsensusTypeMigration is disabled
    89  		if !b.channelConfig.Capabilities().ConsensusTypeMigration() {
    90  			if oc.ConsensusType() != noc.ConsensusType() {
    91  				return errors.Errorf("attempted to change consensus type from %s to %s",
    92  					oc.ConsensusType(), noc.ConsensusType())
    93  			}
    94  		}
    95  
    96  		for orgName, org := range oc.Organizations() {
    97  			norg, ok := noc.Organizations()[orgName]
    98  			if !ok {
    99  				continue
   100  			}
   101  			mspID := org.MSPID()
   102  			if mspID != norg.MSPID() {
   103  				return errors.Errorf("orderer org %s attempted to change MSP ID from %s to %s", orgName, mspID, norg.MSPID())
   104  			}
   105  		}
   106  	}
   107  
   108  	if ac, ok := b.ApplicationConfig(); ok {
   109  		nac, ok := nb.ApplicationConfig()
   110  		if !ok {
   111  			return errors.New("current config has application section, but new config does not")
   112  		}
   113  
   114  		for orgName, org := range ac.Organizations() {
   115  			norg, ok := nac.Organizations()[orgName]
   116  			if !ok {
   117  				continue
   118  			}
   119  			mspID := org.MSPID()
   120  			if mspID != norg.MSPID() {
   121  				return errors.Errorf("application org %s attempted to change MSP ID from %s to %s", orgName, mspID, norg.MSPID())
   122  			}
   123  		}
   124  	}
   125  
   126  	if cc, ok := b.ConsortiumsConfig(); ok {
   127  		ncc, ok := nb.ConsortiumsConfig()
   128  		if !ok {
   129  			return errors.Errorf("current config has consortiums section, but new config does not")
   130  		}
   131  
   132  		for consortiumName, consortium := range cc.Consortiums() {
   133  			nconsortium, ok := ncc.Consortiums()[consortiumName]
   134  			if !ok {
   135  				continue
   136  			}
   137  
   138  			for orgName, org := range consortium.Organizations() {
   139  				norg, ok := nconsortium.Organizations()[orgName]
   140  				if !ok {
   141  					continue
   142  				}
   143  				mspID := org.MSPID()
   144  				if mspID != norg.MSPID() {
   145  					return errors.Errorf("consortium %s org %s attempted to change MSP ID from %s to %s", consortiumName, orgName, mspID, norg.MSPID())
   146  				}
   147  			}
   148  		}
   149  	} else if _, okNew := nb.ConsortiumsConfig(); okNew {
   150  		return errors.Errorf("current config has no consortiums section, but new config does")
   151  	}
   152  
   153  	return nil
   154  }
   155  
   156  // NewBundleFromEnvelope wraps the NewBundle function, extracting the needed
   157  // information from a full configtx
   158  func NewBundleFromEnvelope(env *cb.Envelope, bccsp bccsp.BCCSP) (*Bundle, error) {
   159  	payload, err := protoutil.UnmarshalPayload(env.Payload)
   160  	if err != nil {
   161  		return nil, errors.Wrap(err, "failed to unmarshal payload from envelope")
   162  	}
   163  
   164  	configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data)
   165  	if err != nil {
   166  		return nil, errors.Wrap(err, "failed to unmarshal config envelope from payload")
   167  	}
   168  
   169  	if payload.Header == nil {
   170  		return nil, errors.Errorf("envelope header cannot be nil")
   171  	}
   172  
   173  	chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   174  	if err != nil {
   175  		return nil, errors.Wrap(err, "failed to unmarshal channel header")
   176  	}
   177  
   178  	return NewBundle(chdr.ChannelId, configEnvelope.Config, bccsp)
   179  }
   180  
   181  // NewBundle creates a new immutable bundle of configuration
   182  func NewBundle(channelID string, config *cb.Config, bccsp bccsp.BCCSP) (*Bundle, error) {
   183  	if err := preValidate(config); err != nil {
   184  		return nil, err
   185  	}
   186  
   187  	channelConfig, err := NewChannelConfig(config.ChannelGroup, bccsp)
   188  	if err != nil {
   189  		return nil, errors.Wrap(err, "initializing channelconfig failed")
   190  	}
   191  
   192  	policyProviderMap := make(map[int32]policies.Provider)
   193  	for pType := range cb.Policy_PolicyType_name {
   194  		rtype := cb.Policy_PolicyType(pType)
   195  		switch rtype {
   196  		case cb.Policy_UNKNOWN:
   197  			// Do not register a handler
   198  		case cb.Policy_SIGNATURE:
   199  			policyProviderMap[pType] = cauthdsl.NewPolicyProvider(channelConfig.MSPManager())
   200  		case cb.Policy_MSP:
   201  			// Add hook for MSP Handler here
   202  		}
   203  	}
   204  
   205  	policyManager, err := policies.NewManagerImpl(RootGroupKey, policyProviderMap, config.ChannelGroup)
   206  	if err != nil {
   207  		return nil, errors.Wrap(err, "initializing policymanager failed")
   208  	}
   209  
   210  	configtxManager, err := configtx.NewValidatorImpl(channelID, config, RootGroupKey, policyManager)
   211  	if err != nil {
   212  		return nil, errors.Wrap(err, "initializing configtx manager failed")
   213  	}
   214  
   215  	return &Bundle{
   216  		policyManager:   policyManager,
   217  		channelConfig:   channelConfig,
   218  		configtxManager: configtxManager,
   219  	}, nil
   220  }
   221  
   222  func preValidate(config *cb.Config) error {
   223  	if config == nil {
   224  		return errors.New("channelconfig Config cannot be nil")
   225  	}
   226  
   227  	if config.ChannelGroup == nil {
   228  		return errors.New("config must contain a channel group")
   229  	}
   230  
   231  	if og, ok := config.ChannelGroup.Groups[OrdererGroupKey]; ok {
   232  		if _, ok := og.Values[CapabilitiesKey]; !ok {
   233  			if _, ok := config.ChannelGroup.Values[CapabilitiesKey]; ok {
   234  				return errors.New("cannot enable channel capabilities without orderer support first")
   235  			}
   236  
   237  			if ag, ok := config.ChannelGroup.Groups[ApplicationGroupKey]; ok {
   238  				if _, ok := ag.Values[CapabilitiesKey]; ok {
   239  					return errors.New("cannot enable application capabilities without orderer support first")
   240  				}
   241  			}
   242  		}
   243  	}
   244  
   245  	return nil
   246  }