github.com/kaituanwang/hyperledger@v2.0.1+incompatible/internal/configtxgen/genesisconfig/config.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package genesisconfig
     8  
     9  import (
    10  	"path/filepath"
    11  	"time"
    12  
    13  	"github.com/hyperledger/fabric-protos-go/orderer/etcdraft"
    14  	"github.com/hyperledger/fabric/common/flogging"
    15  	"github.com/hyperledger/fabric/common/policies"
    16  	"github.com/hyperledger/fabric/common/viperutil"
    17  	cf "github.com/hyperledger/fabric/core/config"
    18  	"github.com/hyperledger/fabric/msp"
    19  	"github.com/spf13/viper"
    20  )
    21  
    22  const (
    23  	// The type key for etcd based RAFT consensus.
    24  	EtcdRaft = "etcdraft"
    25  )
    26  
    27  var logger = flogging.MustGetLogger("common.tools.configtxgen.localconfig")
    28  
    29  const (
    30  	// SampleInsecureSoloProfile references the sample profile which does not
    31  	// include any MSPs and uses solo for ordering.
    32  	SampleInsecureSoloProfile = "SampleInsecureSolo"
    33  	// SampleDevModeSoloProfile references the sample profile which requires
    34  	// only basic membership for admin privileges and uses solo for ordering.
    35  	SampleDevModeSoloProfile = "SampleDevModeSolo"
    36  	// SampleSingleMSPSoloProfile references the sample profile which includes
    37  	// only the sample MSP and uses solo for ordering.
    38  	SampleSingleMSPSoloProfile = "SampleSingleMSPSolo"
    39  
    40  	// SampleInsecureKafkaProfile references the sample profile which does not
    41  	// include any MSPs and uses Kafka for ordering.
    42  	SampleInsecureKafkaProfile = "SampleInsecureKafka"
    43  	// SampleDevModeKafkaProfile references the sample profile which requires only
    44  	// basic membership for admin privileges and uses Kafka for ordering.
    45  	SampleDevModeKafkaProfile = "SampleDevModeKafka"
    46  	// SampleSingleMSPKafkaProfile references the sample profile which includes
    47  	// only the sample MSP and uses Kafka for ordering.
    48  	SampleSingleMSPKafkaProfile = "SampleSingleMSPKafka"
    49  
    50  	// SampleDevModeEtcdRaftProfile references the sample profile used for testing
    51  	// the etcd/raft-based ordering service.
    52  	SampleDevModeEtcdRaftProfile = "SampleDevModeEtcdRaft"
    53  
    54  	// SampleSingleMSPChannelProfile references the sample profile which
    55  	// includes only the sample MSP and is used to create a channel
    56  	SampleSingleMSPChannelProfile = "SampleSingleMSPChannel"
    57  
    58  	// SampleConsortiumName is the sample consortium from the
    59  	// sample configtx.yaml
    60  	SampleConsortiumName = "SampleConsortium"
    61  	// SampleOrgName is the name of the sample org in the sample profiles
    62  	SampleOrgName = "SampleOrg"
    63  
    64  	// AdminRoleAdminPrincipal is set as AdminRole to cause the MSP role of
    65  	// type Admin to be used as the admin principal default
    66  	AdminRoleAdminPrincipal = "Role.ADMIN"
    67  )
    68  
    69  // TopLevel consists of the structs used by the configtxgen tool.
    70  type TopLevel struct {
    71  	Profiles      map[string]*Profile        `yaml:"Profiles"`
    72  	Organizations []*Organization            `yaml:"Organizations"`
    73  	Channel       *Profile                   `yaml:"Channel"`
    74  	Application   *Application               `yaml:"Application"`
    75  	Orderer       *Orderer                   `yaml:"Orderer"`
    76  	Capabilities  map[string]map[string]bool `yaml:"Capabilities"`
    77  	Resources     *Resources                 `yaml:"Resources"`
    78  }
    79  
    80  // Profile encodes orderer/application configuration combinations for the
    81  // configtxgen tool.
    82  type Profile struct {
    83  	Consortium   string                 `yaml:"Consortium"`
    84  	Application  *Application           `yaml:"Application"`
    85  	Orderer      *Orderer               `yaml:"Orderer"`
    86  	Consortiums  map[string]*Consortium `yaml:"Consortiums"`
    87  	Capabilities map[string]bool        `yaml:"Capabilities"`
    88  	Policies     map[string]*Policy     `yaml:"Policies"`
    89  }
    90  
    91  // Policy encodes a channel config policy
    92  type Policy struct {
    93  	Type string `yaml:"Type"`
    94  	Rule string `yaml:"Rule"`
    95  }
    96  
    97  // Consortium represents a group of organizations which may create channels
    98  // with each other
    99  type Consortium struct {
   100  	Organizations []*Organization `yaml:"Organizations"`
   101  }
   102  
   103  // Application encodes the application-level configuration needed in config
   104  // transactions.
   105  type Application struct {
   106  	Organizations []*Organization    `yaml:"Organizations"`
   107  	Capabilities  map[string]bool    `yaml:"Capabilities"`
   108  	Resources     *Resources         `yaml:"Resources"`
   109  	Policies      map[string]*Policy `yaml:"Policies"`
   110  	ACLs          map[string]string  `yaml:"ACLs"`
   111  }
   112  
   113  // Resources encodes the application-level resources configuration needed to
   114  // seed the resource tree
   115  type Resources struct {
   116  	DefaultModPolicy string
   117  }
   118  
   119  // Organization encodes the organization-level configuration needed in
   120  // config transactions.
   121  type Organization struct {
   122  	Name     string             `yaml:"Name"`
   123  	ID       string             `yaml:"ID"`
   124  	MSPDir   string             `yaml:"MSPDir"`
   125  	MSPType  string             `yaml:"MSPType"`
   126  	Policies map[string]*Policy `yaml:"Policies"`
   127  
   128  	// Note: Viper deserialization does not seem to care for
   129  	// embedding of types, so we use one organization struct
   130  	// for both orderers and applications.
   131  	AnchorPeers      []*AnchorPeer `yaml:"AnchorPeers"`
   132  	OrdererEndpoints []string      `yaml:"OrdererEndpoints"`
   133  
   134  	// AdminPrincipal is deprecated and may be removed in a future release
   135  	// it was used for modifying the default policy generation, but policies
   136  	// may now be specified explicitly so it is redundant and unnecessary
   137  	AdminPrincipal string `yaml:"AdminPrincipal"`
   138  
   139  	// SkipAsForeign indicates that this org definition is actually unknown to this
   140  	// instance of the tool, so, parsing of this org's parameters should be ignored.
   141  	SkipAsForeign bool
   142  }
   143  
   144  // AnchorPeer encodes the necessary fields to identify an anchor peer.
   145  type AnchorPeer struct {
   146  	Host string `yaml:"Host"`
   147  	Port int    `yaml:"Port"`
   148  }
   149  
   150  // Orderer contains configuration associated to a channel.
   151  type Orderer struct {
   152  	OrdererType   string                   `yaml:"OrdererType"`
   153  	Addresses     []string                 `yaml:"Addresses"`
   154  	BatchTimeout  time.Duration            `yaml:"BatchTimeout"`
   155  	BatchSize     BatchSize                `yaml:"BatchSize"`
   156  	Kafka         Kafka                    `yaml:"Kafka"`
   157  	EtcdRaft      *etcdraft.ConfigMetadata `yaml:"EtcdRaft"`
   158  	Organizations []*Organization          `yaml:"Organizations"`
   159  	MaxChannels   uint64                   `yaml:"MaxChannels"`
   160  	Capabilities  map[string]bool          `yaml:"Capabilities"`
   161  	Policies      map[string]*Policy       `yaml:"Policies"`
   162  }
   163  
   164  // BatchSize contains configuration affecting the size of batches.
   165  type BatchSize struct {
   166  	MaxMessageCount   uint32 `yaml:"MaxMessageCount"`
   167  	AbsoluteMaxBytes  uint32 `yaml:"AbsoluteMaxBytes"`
   168  	PreferredMaxBytes uint32 `yaml:"PreferredMaxBytes"`
   169  }
   170  
   171  // Kafka contains configuration for the Kafka-based orderer.
   172  type Kafka struct {
   173  	Brokers []string `yaml:"Brokers"`
   174  }
   175  
   176  var genesisDefaults = TopLevel{
   177  	Orderer: &Orderer{
   178  		OrdererType:  "solo",
   179  		Addresses:    []string{"127.0.0.1:7050"},
   180  		BatchTimeout: 2 * time.Second,
   181  		BatchSize: BatchSize{
   182  			MaxMessageCount:   500,
   183  			AbsoluteMaxBytes:  10 * 1024 * 1024,
   184  			PreferredMaxBytes: 2 * 1024 * 1024,
   185  		},
   186  		Kafka: Kafka{
   187  			Brokers: []string{"127.0.0.1:9092"},
   188  		},
   189  		EtcdRaft: &etcdraft.ConfigMetadata{
   190  			Options: &etcdraft.Options{
   191  				TickInterval:         "500ms",
   192  				ElectionTick:         10,
   193  				HeartbeatTick:        1,
   194  				MaxInflightBlocks:    5,
   195  				SnapshotIntervalSize: 16 * 1024 * 1024, // 16 MB
   196  			},
   197  		},
   198  	},
   199  }
   200  
   201  // LoadTopLevel simply loads the configtx.yaml file into the structs above and
   202  // completes their initialization. Config paths may optionally be provided and
   203  // will be used in place of the FABRIC_CFG_PATH env variable.
   204  //
   205  // Note, for environment overrides to work properly within a profile, Load
   206  // should be used instead.
   207  func LoadTopLevel(configPaths ...string) *TopLevel {
   208  	config := viper.New()
   209  	if len(configPaths) > 0 {
   210  		for _, p := range configPaths {
   211  			config.AddConfigPath(p)
   212  		}
   213  		config.SetConfigName("configtx")
   214  	} else {
   215  		cf.InitViper(config, "configtx")
   216  	}
   217  
   218  	err := config.ReadInConfig()
   219  	if err != nil {
   220  		logger.Panic("Error reading configuration: ", err)
   221  	}
   222  	logger.Debugf("Using config file: %s", config.ConfigFileUsed())
   223  
   224  	var uconf TopLevel
   225  	err = viperutil.EnhancedExactUnmarshal(config, &uconf)
   226  	if err != nil {
   227  		logger.Panic("Error unmarshaling config into struct: ", err)
   228  	}
   229  
   230  	(&uconf).completeInitialization(filepath.Dir(config.ConfigFileUsed()))
   231  
   232  	logger.Infof("Loaded configuration: %s", config.ConfigFileUsed())
   233  
   234  	return &uconf
   235  }
   236  
   237  // Load returns the orderer/application config combination that corresponds to
   238  // a given profile. Config paths may optionally be provided and will be used
   239  // in place of the FABRIC_CFG_PATH env variable.
   240  func Load(profile string, configPaths ...string) *Profile {
   241  	config := viper.New()
   242  	if len(configPaths) > 0 {
   243  		for _, p := range configPaths {
   244  			config.AddConfigPath(p)
   245  		}
   246  		config.SetConfigName("configtx")
   247  	} else {
   248  		cf.InitViper(config, "configtx")
   249  	}
   250  
   251  	err := config.ReadInConfig()
   252  	if err != nil {
   253  		logger.Panic("Error reading configuration: ", err)
   254  	}
   255  	logger.Debugf("Using config file: %s", config.ConfigFileUsed())
   256  
   257  	var uconf TopLevel
   258  	err = viperutil.EnhancedExactUnmarshal(config, &uconf)
   259  	if err != nil {
   260  		logger.Panic("Error unmarshaling config into struct: ", err)
   261  	}
   262  
   263  	result, ok := uconf.Profiles[profile]
   264  	if !ok {
   265  		logger.Panic("Could not find profile: ", profile)
   266  	}
   267  
   268  	result.completeInitialization(filepath.Dir(config.ConfigFileUsed()))
   269  
   270  	logger.Infof("Loaded configuration: %s", config.ConfigFileUsed())
   271  
   272  	return result
   273  }
   274  
   275  func (t *TopLevel) completeInitialization(configDir string) {
   276  	for _, org := range t.Organizations {
   277  		org.completeInitialization(configDir)
   278  	}
   279  
   280  	if t.Orderer != nil {
   281  		t.Orderer.completeInitialization(configDir)
   282  	}
   283  }
   284  
   285  func (p *Profile) completeInitialization(configDir string) {
   286  	if p.Application != nil {
   287  		for _, org := range p.Application.Organizations {
   288  			org.completeInitialization(configDir)
   289  		}
   290  		if p.Application.Resources != nil {
   291  			p.Application.Resources.completeInitialization()
   292  		}
   293  	}
   294  
   295  	if p.Consortiums != nil {
   296  		for _, consortium := range p.Consortiums {
   297  			for _, org := range consortium.Organizations {
   298  				org.completeInitialization(configDir)
   299  			}
   300  		}
   301  	}
   302  
   303  	if p.Orderer != nil {
   304  		for _, org := range p.Orderer.Organizations {
   305  			org.completeInitialization(configDir)
   306  		}
   307  		// Some profiles will not define orderer parameters
   308  		p.Orderer.completeInitialization(configDir)
   309  	}
   310  }
   311  
   312  func (r *Resources) completeInitialization() {
   313  	for {
   314  		switch {
   315  		case r.DefaultModPolicy == "":
   316  			r.DefaultModPolicy = policies.ChannelApplicationAdmins
   317  		default:
   318  			return
   319  		}
   320  	}
   321  }
   322  
   323  func (org *Organization) completeInitialization(configDir string) {
   324  	// set the MSP type; if none is specified we assume BCCSP
   325  	if org.MSPType == "" {
   326  		org.MSPType = msp.ProviderTypeToString(msp.FABRIC)
   327  	}
   328  
   329  	if org.AdminPrincipal == "" {
   330  		org.AdminPrincipal = AdminRoleAdminPrincipal
   331  	}
   332  	translatePaths(configDir, org)
   333  }
   334  
   335  func (ord *Orderer) completeInitialization(configDir string) {
   336  loop:
   337  	for {
   338  		switch {
   339  		case ord.OrdererType == "":
   340  			logger.Infof("Orderer.OrdererType unset, setting to %v", genesisDefaults.Orderer.OrdererType)
   341  			ord.OrdererType = genesisDefaults.Orderer.OrdererType
   342  		case ord.Addresses == nil:
   343  			logger.Infof("Orderer.Addresses unset, setting to %s", genesisDefaults.Orderer.Addresses)
   344  			ord.Addresses = genesisDefaults.Orderer.Addresses
   345  		case ord.BatchTimeout == 0:
   346  			logger.Infof("Orderer.BatchTimeout unset, setting to %s", genesisDefaults.Orderer.BatchTimeout)
   347  			ord.BatchTimeout = genesisDefaults.Orderer.BatchTimeout
   348  		case ord.BatchSize.MaxMessageCount == 0:
   349  			logger.Infof("Orderer.BatchSize.MaxMessageCount unset, setting to %v", genesisDefaults.Orderer.BatchSize.MaxMessageCount)
   350  			ord.BatchSize.MaxMessageCount = genesisDefaults.Orderer.BatchSize.MaxMessageCount
   351  		case ord.BatchSize.AbsoluteMaxBytes == 0:
   352  			logger.Infof("Orderer.BatchSize.AbsoluteMaxBytes unset, setting to %v", genesisDefaults.Orderer.BatchSize.AbsoluteMaxBytes)
   353  			ord.BatchSize.AbsoluteMaxBytes = genesisDefaults.Orderer.BatchSize.AbsoluteMaxBytes
   354  		case ord.BatchSize.PreferredMaxBytes == 0:
   355  			logger.Infof("Orderer.BatchSize.PreferredMaxBytes unset, setting to %v", genesisDefaults.Orderer.BatchSize.PreferredMaxBytes)
   356  			ord.BatchSize.PreferredMaxBytes = genesisDefaults.Orderer.BatchSize.PreferredMaxBytes
   357  		default:
   358  			break loop
   359  		}
   360  	}
   361  
   362  	logger.Infof("orderer type: %s", ord.OrdererType)
   363  	// Additional, consensus type-dependent initialization goes here
   364  	// Also using this to panic on unknown orderer type.
   365  	switch ord.OrdererType {
   366  	case "solo":
   367  		// nothing to be done here
   368  	case "kafka":
   369  		if ord.Kafka.Brokers == nil {
   370  			logger.Infof("Orderer.Kafka unset, setting to %v", genesisDefaults.Orderer.Kafka.Brokers)
   371  			ord.Kafka.Brokers = genesisDefaults.Orderer.Kafka.Brokers
   372  		}
   373  	case EtcdRaft:
   374  		if ord.EtcdRaft == nil {
   375  			logger.Panicf("%s configuration missing", EtcdRaft)
   376  		}
   377  		if ord.EtcdRaft.Options == nil {
   378  			logger.Infof("Orderer.EtcdRaft.Options unset, setting to %v", genesisDefaults.Orderer.EtcdRaft.Options)
   379  			ord.EtcdRaft.Options = genesisDefaults.Orderer.EtcdRaft.Options
   380  		}
   381  	second_loop:
   382  		for {
   383  			switch {
   384  			case ord.EtcdRaft.Options.TickInterval == "":
   385  				logger.Infof("Orderer.EtcdRaft.Options.TickInterval unset, setting to %v", genesisDefaults.Orderer.EtcdRaft.Options.TickInterval)
   386  				ord.EtcdRaft.Options.TickInterval = genesisDefaults.Orderer.EtcdRaft.Options.TickInterval
   387  
   388  			case ord.EtcdRaft.Options.ElectionTick == 0:
   389  				logger.Infof("Orderer.EtcdRaft.Options.ElectionTick unset, setting to %v", genesisDefaults.Orderer.EtcdRaft.Options.ElectionTick)
   390  				ord.EtcdRaft.Options.ElectionTick = genesisDefaults.Orderer.EtcdRaft.Options.ElectionTick
   391  
   392  			case ord.EtcdRaft.Options.HeartbeatTick == 0:
   393  				logger.Infof("Orderer.EtcdRaft.Options.HeartbeatTick unset, setting to %v", genesisDefaults.Orderer.EtcdRaft.Options.HeartbeatTick)
   394  				ord.EtcdRaft.Options.HeartbeatTick = genesisDefaults.Orderer.EtcdRaft.Options.HeartbeatTick
   395  
   396  			case ord.EtcdRaft.Options.MaxInflightBlocks == 0:
   397  				logger.Infof("Orderer.EtcdRaft.Options.MaxInflightBlocks unset, setting to %v", genesisDefaults.Orderer.EtcdRaft.Options.MaxInflightBlocks)
   398  				ord.EtcdRaft.Options.MaxInflightBlocks = genesisDefaults.Orderer.EtcdRaft.Options.MaxInflightBlocks
   399  
   400  			case ord.EtcdRaft.Options.SnapshotIntervalSize == 0:
   401  				logger.Infof("Orderer.EtcdRaft.Options.SnapshotIntervalSize unset, setting to %v", genesisDefaults.Orderer.EtcdRaft.Options.SnapshotIntervalSize)
   402  				ord.EtcdRaft.Options.SnapshotIntervalSize = genesisDefaults.Orderer.EtcdRaft.Options.SnapshotIntervalSize
   403  
   404  			case len(ord.EtcdRaft.Consenters) == 0:
   405  				logger.Panicf("%s configuration did not specify any consenter", EtcdRaft)
   406  
   407  			default:
   408  				break second_loop
   409  			}
   410  		}
   411  
   412  		if _, err := time.ParseDuration(ord.EtcdRaft.Options.TickInterval); err != nil {
   413  			logger.Panicf("Etcdraft TickInterval (%s) must be in time duration format", ord.EtcdRaft.Options.TickInterval)
   414  		}
   415  
   416  		// validate the specified members for Options
   417  		if ord.EtcdRaft.Options.ElectionTick <= ord.EtcdRaft.Options.HeartbeatTick {
   418  			logger.Panicf("election tick must be greater than heartbeat tick")
   419  		}
   420  
   421  		for _, c := range ord.EtcdRaft.GetConsenters() {
   422  			if c.Host == "" {
   423  				logger.Panicf("consenter info in %s configuration did not specify host", EtcdRaft)
   424  			}
   425  			if c.Port == 0 {
   426  				logger.Panicf("consenter info in %s configuration did not specify port", EtcdRaft)
   427  			}
   428  			if c.ClientTlsCert == nil {
   429  				logger.Panicf("consenter info in %s configuration did not specify client TLS cert", EtcdRaft)
   430  			}
   431  			if c.ServerTlsCert == nil {
   432  				logger.Panicf("consenter info in %s configuration did not specify server TLS cert", EtcdRaft)
   433  			}
   434  			clientCertPath := string(c.GetClientTlsCert())
   435  			cf.TranslatePathInPlace(configDir, &clientCertPath)
   436  			c.ClientTlsCert = []byte(clientCertPath)
   437  			serverCertPath := string(c.GetServerTlsCert())
   438  			cf.TranslatePathInPlace(configDir, &serverCertPath)
   439  			c.ServerTlsCert = []byte(serverCertPath)
   440  		}
   441  	default:
   442  		logger.Panicf("unknown orderer type: %s", ord.OrdererType)
   443  	}
   444  }
   445  
   446  func translatePaths(configDir string, org *Organization) {
   447  	cf.TranslatePathInPlace(configDir, &org.MSPDir)
   448  }