github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/internal/configtxgen/genesisconfig/config.go (about)

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