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