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 }