github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/internal/configtxgen/encoder/encoder.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package encoder
     8  
     9  import (
    10  	"github.com/golang/protobuf/proto"
    11  	cb "github.com/hyperledger/fabric-protos-go/common"
    12  	pb "github.com/hyperledger/fabric-protos-go/peer"
    13  	"github.com/hyperledger/fabric/common/cauthdsl"
    14  	"github.com/hyperledger/fabric/common/channelconfig"
    15  	"github.com/hyperledger/fabric/common/flogging"
    16  	"github.com/hyperledger/fabric/common/genesis"
    17  	"github.com/hyperledger/fabric/common/policies"
    18  	"github.com/hyperledger/fabric/common/util"
    19  	"github.com/hyperledger/fabric/internal/configtxgen/genesisconfig"
    20  	"github.com/hyperledger/fabric/internal/configtxlator/update"
    21  	"github.com/hyperledger/fabric/internal/pkg/identity"
    22  	"github.com/hyperledger/fabric/msp"
    23  	"github.com/hyperledger/fabric/protoutil"
    24  	"github.com/pkg/errors"
    25  )
    26  
    27  const (
    28  	ordererAdminsPolicyName = "/Channel/Orderer/Admins"
    29  
    30  	msgVersion = int32(0)
    31  	epoch      = 0
    32  )
    33  
    34  var logger = flogging.MustGetLogger("common.tools.configtxgen.encoder")
    35  
    36  const (
    37  	// ConsensusTypeSolo identifies the solo consensus implementation.
    38  	ConsensusTypeSolo = "solo"
    39  	// ConsensusTypeKafka identifies the Kafka-based consensus implementation.
    40  	ConsensusTypeKafka = "kafka"
    41  	// ConsensusTypeKafka identifies the Kafka-based consensus implementation.
    42  	ConsensusTypeEtcdRaft = "etcdraft"
    43  
    44  	// BlockValidationPolicyKey TODO
    45  	BlockValidationPolicyKey = "BlockValidation"
    46  
    47  	// OrdererAdminsPolicy is the absolute path to the orderer admins policy
    48  	OrdererAdminsPolicy = "/Channel/Orderer/Admins"
    49  
    50  	// SignaturePolicyType is the 'Type' string for signature policies
    51  	SignaturePolicyType = "Signature"
    52  
    53  	// ImplicitMetaPolicyType is the 'Type' string for implicit meta policies
    54  	ImplicitMetaPolicyType = "ImplicitMeta"
    55  )
    56  
    57  func addValue(cg *cb.ConfigGroup, value channelconfig.ConfigValue, modPolicy string) {
    58  	cg.Values[value.Key()] = &cb.ConfigValue{
    59  		Value:     protoutil.MarshalOrPanic(value.Value()),
    60  		ModPolicy: modPolicy,
    61  	}
    62  }
    63  
    64  func addPolicy(cg *cb.ConfigGroup, policy policies.ConfigPolicy, modPolicy string) {
    65  	cg.Policies[policy.Key()] = &cb.ConfigPolicy{
    66  		Policy:    policy.Value(),
    67  		ModPolicy: modPolicy,
    68  	}
    69  }
    70  
    71  func AddPolicies(cg *cb.ConfigGroup, policyMap map[string]*genesisconfig.Policy, modPolicy string) error {
    72  	switch {
    73  	case policyMap == nil:
    74  		return errors.Errorf("no policies defined")
    75  	case policyMap[channelconfig.AdminsPolicyKey] == nil:
    76  		return errors.Errorf("no Admins policy defined")
    77  	case policyMap[channelconfig.ReadersPolicyKey] == nil:
    78  		return errors.Errorf("no Readers policy defined")
    79  	case policyMap[channelconfig.WritersPolicyKey] == nil:
    80  		return errors.Errorf("no Writers policy defined")
    81  	}
    82  
    83  	for policyName, policy := range policyMap {
    84  		switch policy.Type {
    85  		case ImplicitMetaPolicyType:
    86  			imp, err := policies.ImplicitMetaFromString(policy.Rule)
    87  			if err != nil {
    88  				return errors.Wrapf(err, "invalid implicit meta policy rule '%s'", policy.Rule)
    89  			}
    90  			cg.Policies[policyName] = &cb.ConfigPolicy{
    91  				ModPolicy: modPolicy,
    92  				Policy: &cb.Policy{
    93  					Type:  int32(cb.Policy_IMPLICIT_META),
    94  					Value: protoutil.MarshalOrPanic(imp),
    95  				},
    96  			}
    97  		case SignaturePolicyType:
    98  			sp, err := cauthdsl.FromString(policy.Rule)
    99  			if err != nil {
   100  				return errors.Wrapf(err, "invalid signature policy rule '%s'", policy.Rule)
   101  			}
   102  			cg.Policies[policyName] = &cb.ConfigPolicy{
   103  				ModPolicy: modPolicy,
   104  				Policy: &cb.Policy{
   105  					Type:  int32(cb.Policy_SIGNATURE),
   106  					Value: protoutil.MarshalOrPanic(sp),
   107  				},
   108  			}
   109  		default:
   110  			return errors.Errorf("unknown policy type: %s", policy.Type)
   111  		}
   112  	}
   113  	return nil
   114  }
   115  
   116  // NewChannelGroup defines the root of the channel configuration.  It defines basic operating principles like the hashing
   117  // algorithm used for the blocks, as well as the location of the ordering service.  It will recursively call into the
   118  // NewOrdererGroup, NewConsortiumsGroup, and NewApplicationGroup depending on whether these sub-elements are set in the
   119  // configuration.  All mod_policy values are set to "Admins" for this group, with the exception of the OrdererAddresses
   120  // value which is set to "/Channel/Orderer/Admins".
   121  func NewChannelGroup(conf *genesisconfig.Profile) (*cb.ConfigGroup, error) {
   122  	channelGroup := protoutil.NewConfigGroup()
   123  	if err := AddPolicies(channelGroup, conf.Policies, channelconfig.AdminsPolicyKey); err != nil {
   124  		return nil, errors.Wrapf(err, "error adding policies to channel group")
   125  	}
   126  
   127  	addValue(channelGroup, channelconfig.HashingAlgorithmValue(), channelconfig.AdminsPolicyKey)
   128  	addValue(channelGroup, channelconfig.BlockDataHashingStructureValue(), channelconfig.AdminsPolicyKey)
   129  	if conf.Orderer != nil && len(conf.Orderer.Addresses) > 0 {
   130  		addValue(channelGroup, channelconfig.OrdererAddressesValue(conf.Orderer.Addresses), ordererAdminsPolicyName)
   131  	}
   132  
   133  	if conf.Consortium != "" {
   134  		addValue(channelGroup, channelconfig.ConsortiumValue(conf.Consortium), channelconfig.AdminsPolicyKey)
   135  	}
   136  
   137  	if len(conf.Capabilities) > 0 {
   138  		addValue(channelGroup, channelconfig.CapabilitiesValue(conf.Capabilities), channelconfig.AdminsPolicyKey)
   139  	}
   140  
   141  	var err error
   142  	if conf.Orderer != nil {
   143  		channelGroup.Groups[channelconfig.OrdererGroupKey], err = NewOrdererGroup(conf.Orderer)
   144  		if err != nil {
   145  			return nil, errors.Wrap(err, "could not create orderer group")
   146  		}
   147  	}
   148  
   149  	if conf.Application != nil {
   150  		channelGroup.Groups[channelconfig.ApplicationGroupKey], err = NewApplicationGroup(conf.Application)
   151  		if err != nil {
   152  			return nil, errors.Wrap(err, "could not create application group")
   153  		}
   154  	}
   155  
   156  	if conf.Consortiums != nil {
   157  		channelGroup.Groups[channelconfig.ConsortiumsGroupKey], err = NewConsortiumsGroup(conf.Consortiums)
   158  		if err != nil {
   159  			return nil, errors.Wrap(err, "could not create consortiums group")
   160  		}
   161  	}
   162  
   163  	channelGroup.ModPolicy = channelconfig.AdminsPolicyKey
   164  	return channelGroup, nil
   165  }
   166  
   167  // NewOrdererGroup returns the orderer component of the channel configuration.  It defines parameters of the ordering service
   168  // about how large blocks should be, how frequently they should be emitted, etc. as well as the organizations of the ordering network.
   169  // It sets the mod_policy of all elements to "Admins".  This group is always present in any channel configuration.
   170  func NewOrdererGroup(conf *genesisconfig.Orderer) (*cb.ConfigGroup, error) {
   171  	ordererGroup := protoutil.NewConfigGroup()
   172  	if err := AddPolicies(ordererGroup, conf.Policies, channelconfig.AdminsPolicyKey); err != nil {
   173  		return nil, errors.Wrapf(err, "error adding policies to orderer group")
   174  	}
   175  	ordererGroup.Policies[BlockValidationPolicyKey] = &cb.ConfigPolicy{
   176  		Policy:    policies.ImplicitMetaAnyPolicy(channelconfig.WritersPolicyKey).Value(),
   177  		ModPolicy: channelconfig.AdminsPolicyKey,
   178  	}
   179  	addValue(ordererGroup, channelconfig.BatchSizeValue(
   180  		conf.BatchSize.MaxMessageCount,
   181  		conf.BatchSize.AbsoluteMaxBytes,
   182  		conf.BatchSize.PreferredMaxBytes,
   183  	), channelconfig.AdminsPolicyKey)
   184  	addValue(ordererGroup, channelconfig.BatchTimeoutValue(conf.BatchTimeout.String()), channelconfig.AdminsPolicyKey)
   185  	addValue(ordererGroup, channelconfig.ChannelRestrictionsValue(conf.MaxChannels), channelconfig.AdminsPolicyKey)
   186  
   187  	if len(conf.Capabilities) > 0 {
   188  		addValue(ordererGroup, channelconfig.CapabilitiesValue(conf.Capabilities), channelconfig.AdminsPolicyKey)
   189  	}
   190  
   191  	var consensusMetadata []byte
   192  	var err error
   193  
   194  	switch conf.OrdererType {
   195  	case ConsensusTypeSolo:
   196  	case ConsensusTypeKafka:
   197  		addValue(ordererGroup, channelconfig.KafkaBrokersValue(conf.Kafka.Brokers), channelconfig.AdminsPolicyKey)
   198  	case ConsensusTypeEtcdRaft:
   199  		if consensusMetadata, err = channelconfig.MarshalEtcdRaftMetadata(conf.EtcdRaft); err != nil {
   200  			return nil, errors.Errorf("cannot marshal metadata for orderer type %s: %s", ConsensusTypeEtcdRaft, err)
   201  		}
   202  	default:
   203  		return nil, errors.Errorf("unknown orderer type: %s", conf.OrdererType)
   204  	}
   205  
   206  	addValue(ordererGroup, channelconfig.ConsensusTypeValue(conf.OrdererType, consensusMetadata), channelconfig.AdminsPolicyKey)
   207  
   208  	for _, org := range conf.Organizations {
   209  		var err error
   210  		ordererGroup.Groups[org.Name], err = NewOrdererOrgGroup(org)
   211  		if err != nil {
   212  			return nil, errors.Wrap(err, "failed to create orderer org")
   213  		}
   214  	}
   215  
   216  	ordererGroup.ModPolicy = channelconfig.AdminsPolicyKey
   217  	return ordererGroup, nil
   218  }
   219  
   220  // NewConsortiumsGroup returns an org component of the channel configuration.  It defines the crypto material for the
   221  // organization (its MSP).  It sets the mod_policy of all elements to "Admins".
   222  func NewConsortiumOrgGroup(conf *genesisconfig.Organization) (*cb.ConfigGroup, error) {
   223  	consortiumsOrgGroup := protoutil.NewConfigGroup()
   224  	consortiumsOrgGroup.ModPolicy = channelconfig.AdminsPolicyKey
   225  
   226  	if conf.SkipAsForeign {
   227  		return consortiumsOrgGroup, nil
   228  	}
   229  
   230  	mspConfig, err := msp.GetVerifyingMspConfig(conf.MSPDir, conf.ID, conf.MSPType)
   231  	if err != nil {
   232  		return nil, errors.Wrapf(err, "1 - Error loading MSP configuration for org: %s", conf.Name)
   233  	}
   234  
   235  	if err := AddPolicies(consortiumsOrgGroup, conf.Policies, channelconfig.AdminsPolicyKey); err != nil {
   236  		return nil, errors.Wrapf(err, "error adding policies to consortiums org group '%s'", conf.Name)
   237  	}
   238  
   239  	addValue(consortiumsOrgGroup, channelconfig.MSPValue(mspConfig), channelconfig.AdminsPolicyKey)
   240  
   241  	return consortiumsOrgGroup, nil
   242  }
   243  
   244  // NewOrdererOrgGroup returns an orderer org component of the channel configuration.  It defines the crypto material for the
   245  // organization (its MSP).  It sets the mod_policy of all elements to "Admins".
   246  func NewOrdererOrgGroup(conf *genesisconfig.Organization) (*cb.ConfigGroup, error) {
   247  	ordererOrgGroup := protoutil.NewConfigGroup()
   248  	ordererOrgGroup.ModPolicy = channelconfig.AdminsPolicyKey
   249  
   250  	if conf.SkipAsForeign {
   251  		return ordererOrgGroup, nil
   252  	}
   253  
   254  	mspConfig, err := msp.GetVerifyingMspConfig(conf.MSPDir, conf.ID, conf.MSPType)
   255  	if err != nil {
   256  		return nil, errors.Wrapf(err, "1 - Error loading MSP configuration for org: %s", conf.Name)
   257  	}
   258  
   259  	if err := AddPolicies(ordererOrgGroup, conf.Policies, channelconfig.AdminsPolicyKey); err != nil {
   260  		return nil, errors.Wrapf(err, "error adding policies to orderer org group '%s'", conf.Name)
   261  	}
   262  
   263  	addValue(ordererOrgGroup, channelconfig.MSPValue(mspConfig), channelconfig.AdminsPolicyKey)
   264  
   265  	if len(conf.OrdererEndpoints) > 0 {
   266  		addValue(ordererOrgGroup, channelconfig.EndpointsValue(conf.OrdererEndpoints), channelconfig.AdminsPolicyKey)
   267  	}
   268  
   269  	return ordererOrgGroup, nil
   270  }
   271  
   272  // NewApplicationGroup returns the application component of the channel configuration.  It defines the organizations which are involved
   273  // in application logic like chaincodes, and how these members may interact with the orderer.  It sets the mod_policy of all elements to "Admins".
   274  func NewApplicationGroup(conf *genesisconfig.Application) (*cb.ConfigGroup, error) {
   275  	applicationGroup := protoutil.NewConfigGroup()
   276  	if err := AddPolicies(applicationGroup, conf.Policies, channelconfig.AdminsPolicyKey); err != nil {
   277  		return nil, errors.Wrapf(err, "error adding policies to application group")
   278  	}
   279  
   280  	if len(conf.ACLs) > 0 {
   281  		addValue(applicationGroup, channelconfig.ACLValues(conf.ACLs), channelconfig.AdminsPolicyKey)
   282  	}
   283  
   284  	if len(conf.Capabilities) > 0 {
   285  		addValue(applicationGroup, channelconfig.CapabilitiesValue(conf.Capabilities), channelconfig.AdminsPolicyKey)
   286  	}
   287  
   288  	for _, org := range conf.Organizations {
   289  		var err error
   290  		applicationGroup.Groups[org.Name], err = NewApplicationOrgGroup(org)
   291  		if err != nil {
   292  			return nil, errors.Wrap(err, "failed to create application org")
   293  		}
   294  	}
   295  
   296  	applicationGroup.ModPolicy = channelconfig.AdminsPolicyKey
   297  	return applicationGroup, nil
   298  }
   299  
   300  // NewApplicationOrgGroup returns an application org component of the channel configuration.  It defines the crypto material for the organization
   301  // (its MSP) as well as its anchor peers for use by the gossip network.  It sets the mod_policy of all elements to "Admins".
   302  func NewApplicationOrgGroup(conf *genesisconfig.Organization) (*cb.ConfigGroup, error) {
   303  	applicationOrgGroup := protoutil.NewConfigGroup()
   304  	applicationOrgGroup.ModPolicy = channelconfig.AdminsPolicyKey
   305  
   306  	if conf.SkipAsForeign {
   307  		return applicationOrgGroup, nil
   308  	}
   309  
   310  	mspConfig, err := msp.GetVerifyingMspConfig(conf.MSPDir, conf.ID, conf.MSPType)
   311  	if err != nil {
   312  		return nil, errors.Wrapf(err, "1 - Error loading MSP configuration for org %s", conf.Name)
   313  	}
   314  
   315  	if err := AddPolicies(applicationOrgGroup, conf.Policies, channelconfig.AdminsPolicyKey); err != nil {
   316  		return nil, errors.Wrapf(err, "error adding policies to application org group %s", conf.Name)
   317  	}
   318  	addValue(applicationOrgGroup, channelconfig.MSPValue(mspConfig), channelconfig.AdminsPolicyKey)
   319  
   320  	var anchorProtos []*pb.AnchorPeer
   321  	for _, anchorPeer := range conf.AnchorPeers {
   322  		anchorProtos = append(anchorProtos, &pb.AnchorPeer{
   323  			Host: anchorPeer.Host,
   324  			Port: int32(anchorPeer.Port),
   325  		})
   326  	}
   327  
   328  	// Avoid adding an unnecessary anchor peers element when one is not required.  This helps
   329  	// prevent a delta from the orderer system channel when computing more complex channel
   330  	// creation transactions
   331  	if len(anchorProtos) > 0 {
   332  		addValue(applicationOrgGroup, channelconfig.AnchorPeersValue(anchorProtos), channelconfig.AdminsPolicyKey)
   333  	}
   334  
   335  	return applicationOrgGroup, nil
   336  }
   337  
   338  // NewConsortiumsGroup returns the consortiums component of the channel configuration.  This element is only defined for the ordering system channel.
   339  // It sets the mod_policy for all elements to "/Channel/Orderer/Admins".
   340  func NewConsortiumsGroup(conf map[string]*genesisconfig.Consortium) (*cb.ConfigGroup, error) {
   341  	consortiumsGroup := protoutil.NewConfigGroup()
   342  	// This policy is not referenced anywhere, it is only used as part of the implicit meta policy rule at the channel level, so this setting
   343  	// effectively degrades control of the ordering system channel to the ordering admins
   344  	addPolicy(consortiumsGroup, policies.SignaturePolicy(channelconfig.AdminsPolicyKey, cauthdsl.AcceptAllPolicy), ordererAdminsPolicyName)
   345  
   346  	for consortiumName, consortium := range conf {
   347  		var err error
   348  		consortiumsGroup.Groups[consortiumName], err = NewConsortiumGroup(consortium)
   349  		if err != nil {
   350  			return nil, errors.Wrapf(err, "failed to create consortium %s", consortiumName)
   351  		}
   352  	}
   353  
   354  	consortiumsGroup.ModPolicy = ordererAdminsPolicyName
   355  	return consortiumsGroup, nil
   356  }
   357  
   358  // NewConsortiums returns a consortiums component of the channel configuration.  Each consortium defines the organizations which may be involved in channel
   359  // creation, as well as the channel creation policy the orderer checks at channel creation time to authorize the action.  It sets the mod_policy of all
   360  // elements to "/Channel/Orderer/Admins".
   361  func NewConsortiumGroup(conf *genesisconfig.Consortium) (*cb.ConfigGroup, error) {
   362  	consortiumGroup := protoutil.NewConfigGroup()
   363  
   364  	for _, org := range conf.Organizations {
   365  		var err error
   366  		consortiumGroup.Groups[org.Name], err = NewConsortiumOrgGroup(org)
   367  		if err != nil {
   368  			return nil, errors.Wrap(err, "failed to create consortium org")
   369  		}
   370  	}
   371  
   372  	addValue(consortiumGroup, channelconfig.ChannelCreationPolicyValue(policies.ImplicitMetaAnyPolicy(channelconfig.AdminsPolicyKey).Value()), ordererAdminsPolicyName)
   373  
   374  	consortiumGroup.ModPolicy = ordererAdminsPolicyName
   375  	return consortiumGroup, nil
   376  }
   377  
   378  // NewChannelCreateConfigUpdate generates a ConfigUpdate which can be sent to the orderer to create a new channel.  Optionally, the channel group of the
   379  // ordering system channel may be passed in, and the resulting ConfigUpdate will extract the appropriate versions from this file.
   380  func NewChannelCreateConfigUpdate(channelID string, conf *genesisconfig.Profile, templateConfig *cb.ConfigGroup) (*cb.ConfigUpdate, error) {
   381  	if conf.Application == nil {
   382  		return nil, errors.New("cannot define a new channel with no Application section")
   383  	}
   384  
   385  	if conf.Consortium == "" {
   386  		return nil, errors.New("cannot define a new channel with no Consortium value")
   387  	}
   388  
   389  	newChannelGroup, err := NewChannelGroup(conf)
   390  	if err != nil {
   391  		return nil, errors.Wrapf(err, "could not turn parse profile into channel group")
   392  	}
   393  
   394  	updt, err := update.Compute(&cb.Config{ChannelGroup: templateConfig}, &cb.Config{ChannelGroup: newChannelGroup})
   395  	if err != nil {
   396  		return nil, errors.Wrapf(err, "could not compute update")
   397  	}
   398  
   399  	// Add the consortium name to create the channel for into the write set as required.
   400  	updt.ChannelId = channelID
   401  	updt.ReadSet.Values[channelconfig.ConsortiumKey] = &cb.ConfigValue{Version: 0}
   402  	updt.WriteSet.Values[channelconfig.ConsortiumKey] = &cb.ConfigValue{
   403  		Version: 0,
   404  		Value: protoutil.MarshalOrPanic(&cb.Consortium{
   405  			Name: conf.Consortium,
   406  		}),
   407  	}
   408  
   409  	return updt, nil
   410  }
   411  
   412  // DefaultConfigTemplate generates a config template based on the assumption that
   413  // the input profile is a channel creation template and no system channel context
   414  // is available.
   415  func DefaultConfigTemplate(conf *genesisconfig.Profile) (*cb.ConfigGroup, error) {
   416  	channelGroup, err := NewChannelGroup(conf)
   417  	if err != nil {
   418  		return nil, errors.WithMessage(err, "error parsing configuration")
   419  	}
   420  
   421  	if _, ok := channelGroup.Groups[channelconfig.ApplicationGroupKey]; !ok {
   422  		return nil, errors.New("channel template configs must contain an application section")
   423  	}
   424  
   425  	channelGroup.Groups[channelconfig.ApplicationGroupKey].Values = nil
   426  	channelGroup.Groups[channelconfig.ApplicationGroupKey].Policies = nil
   427  
   428  	return channelGroup, nil
   429  }
   430  
   431  func ConfigTemplateFromGroup(conf *genesisconfig.Profile, cg *cb.ConfigGroup) (*cb.ConfigGroup, error) {
   432  	template := proto.Clone(cg).(*cb.ConfigGroup)
   433  	if template.Groups == nil {
   434  		return nil, errors.Errorf("supplied system channel group has no sub-groups")
   435  	}
   436  
   437  	template.Groups[channelconfig.ApplicationGroupKey] = &cb.ConfigGroup{
   438  		Groups: map[string]*cb.ConfigGroup{},
   439  		Policies: map[string]*cb.ConfigPolicy{
   440  			channelconfig.AdminsPolicyKey: {},
   441  		},
   442  	}
   443  
   444  	consortiums, ok := template.Groups[channelconfig.ConsortiumsGroupKey]
   445  	if !ok {
   446  		return nil, errors.Errorf("supplied system channel group does not appear to be system channel (missing consortiums group)")
   447  	}
   448  
   449  	if consortiums.Groups == nil {
   450  		return nil, errors.Errorf("system channel consortiums group appears to have no consortiums defined")
   451  	}
   452  
   453  	consortium, ok := consortiums.Groups[conf.Consortium]
   454  	if !ok {
   455  		return nil, errors.Errorf("supplied system channel group is missing '%s' consortium", conf.Consortium)
   456  	}
   457  
   458  	if conf.Application == nil {
   459  		return nil, errors.Errorf("supplied channel creation profile does not contain an application section")
   460  	}
   461  
   462  	for _, organization := range conf.Application.Organizations {
   463  		var ok bool
   464  		template.Groups[channelconfig.ApplicationGroupKey].Groups[organization.Name], ok = consortium.Groups[organization.Name]
   465  		if !ok {
   466  			return nil, errors.Errorf("consortium %s does not contain member org %s", conf.Consortium, organization.Name)
   467  		}
   468  	}
   469  	delete(template.Groups, channelconfig.ConsortiumsGroupKey)
   470  
   471  	addValue(template, channelconfig.ConsortiumValue(conf.Consortium), channelconfig.AdminsPolicyKey)
   472  
   473  	return template, nil
   474  }
   475  
   476  // MakeChannelCreationTransaction is a handy utility function for creating transactions for channel creation.
   477  // It assumes the invoker has no system channel context so ignores all but the application section.
   478  func MakeChannelCreationTransaction(
   479  	channelID string,
   480  	signer identity.SignerSerializer,
   481  	conf *genesisconfig.Profile,
   482  ) (*cb.Envelope, error) {
   483  	template, err := DefaultConfigTemplate(conf)
   484  	if err != nil {
   485  		return nil, errors.WithMessage(err, "could not generate default config template")
   486  	}
   487  	return MakeChannelCreationTransactionFromTemplate(channelID, signer, conf, template)
   488  }
   489  
   490  // MakeChannelCreationTransactionWithSystemChannelContext is a utility function for creating channel creation txes.
   491  // It requires a configuration representing the orderer system channel to allow more sophisticated channel creation
   492  // transactions modifying pieces of the configuration like the orderer set.
   493  func MakeChannelCreationTransactionWithSystemChannelContext(
   494  	channelID string,
   495  	signer identity.SignerSerializer,
   496  	conf,
   497  	systemChannelConf *genesisconfig.Profile,
   498  ) (*cb.Envelope, error) {
   499  	cg, err := NewChannelGroup(systemChannelConf)
   500  	if err != nil {
   501  		return nil, errors.WithMessage(err, "could not parse system channel config")
   502  	}
   503  
   504  	template, err := ConfigTemplateFromGroup(conf, cg)
   505  	if err != nil {
   506  		return nil, errors.WithMessage(err, "could not create config template")
   507  	}
   508  
   509  	return MakeChannelCreationTransactionFromTemplate(channelID, signer, conf, template)
   510  }
   511  
   512  // MakeChannelCreationTransactionFromTemplate creates a transaction for creating a channel.  It uses
   513  // the given template to produce the config update set.  Usually, the caller will want to invoke
   514  // MakeChannelCreationTransaction or MakeChannelCreationTransactionWithSystemChannelContext.
   515  func MakeChannelCreationTransactionFromTemplate(
   516  	channelID string,
   517  	signer identity.SignerSerializer,
   518  	conf *genesisconfig.Profile,
   519  	template *cb.ConfigGroup,
   520  ) (*cb.Envelope, error) {
   521  	newChannelConfigUpdate, err := NewChannelCreateConfigUpdate(channelID, conf, template)
   522  	if err != nil {
   523  		return nil, errors.Wrap(err, "config update generation failure")
   524  	}
   525  
   526  	newConfigUpdateEnv := &cb.ConfigUpdateEnvelope{
   527  		ConfigUpdate: protoutil.MarshalOrPanic(newChannelConfigUpdate),
   528  	}
   529  
   530  	if signer != nil {
   531  		sigHeader, err := protoutil.NewSignatureHeader(signer)
   532  		if err != nil {
   533  			return nil, errors.Wrap(err, "creating signature header failed")
   534  		}
   535  
   536  		newConfigUpdateEnv.Signatures = []*cb.ConfigSignature{{
   537  			SignatureHeader: protoutil.MarshalOrPanic(sigHeader),
   538  		}}
   539  
   540  		newConfigUpdateEnv.Signatures[0].Signature, err = signer.Sign(util.ConcatenateBytes(newConfigUpdateEnv.Signatures[0].SignatureHeader, newConfigUpdateEnv.ConfigUpdate))
   541  		if err != nil {
   542  			return nil, errors.Wrap(err, "signature failure over config update")
   543  		}
   544  
   545  	}
   546  
   547  	return protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG_UPDATE, channelID, signer, newConfigUpdateEnv, msgVersion, epoch)
   548  }
   549  
   550  // HasSkippedForeignOrgs is used to detect whether a configuration includes
   551  // org definitions which should not be parsed because this tool is being
   552  // run in a context where the user does not have access to that org's info
   553  func HasSkippedForeignOrgs(conf *genesisconfig.Profile) error {
   554  	var organizations []*genesisconfig.Organization
   555  
   556  	if conf.Orderer != nil {
   557  		organizations = append(organizations, conf.Orderer.Organizations...)
   558  	}
   559  
   560  	if conf.Application != nil {
   561  		organizations = append(organizations, conf.Application.Organizations...)
   562  	}
   563  
   564  	for _, consortium := range conf.Consortiums {
   565  		organizations = append(organizations, consortium.Organizations...)
   566  	}
   567  
   568  	for _, org := range organizations {
   569  		if org.SkipAsForeign {
   570  			return errors.Errorf("organization '%s' is marked to be skipped as foreign", org.Name)
   571  		}
   572  	}
   573  
   574  	return nil
   575  }
   576  
   577  // Bootstrapper is a wrapper around NewChannelConfigGroup which can produce genesis blocks
   578  type Bootstrapper struct {
   579  	channelGroup *cb.ConfigGroup
   580  }
   581  
   582  // NewBootstrapper creates a bootstrapper but returns an error instead of panic-ing
   583  func NewBootstrapper(config *genesisconfig.Profile) (*Bootstrapper, error) {
   584  	if err := HasSkippedForeignOrgs(config); err != nil {
   585  		return nil, errors.WithMessage(err, "all org definitions must be local during bootstrapping")
   586  	}
   587  
   588  	channelGroup, err := NewChannelGroup(config)
   589  	if err != nil {
   590  		return nil, errors.WithMessage(err, "could not create channel group")
   591  	}
   592  
   593  	return &Bootstrapper{
   594  		channelGroup: channelGroup,
   595  	}, nil
   596  }
   597  
   598  // New creates a new Bootstrapper for generating genesis blocks
   599  func New(config *genesisconfig.Profile) *Bootstrapper {
   600  	bs, err := NewBootstrapper(config)
   601  	if err != nil {
   602  		logger.Panicf("Error creating bootsrapper: %s", err)
   603  	}
   604  	return bs
   605  }
   606  
   607  // GenesisBlock produces a genesis block for the default test channel id
   608  func (bs *Bootstrapper) GenesisBlock() *cb.Block {
   609  	// TODO(mjs): remove
   610  	return genesis.NewFactoryImpl(bs.channelGroup).Block("testchannelid")
   611  }
   612  
   613  // GenesisBlockForChannel produces a genesis block for a given channel ID
   614  func (bs *Bootstrapper) GenesisBlockForChannel(channelID string) *cb.Block {
   615  	return genesis.NewFactoryImpl(bs.channelGroup).Block(channelID)
   616  }