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 }