github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/common/configtx/tool/configtxgen/main.go (about) 1 /* 2 Copyright IBM Corp. 2017 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "flag" 23 "fmt" 24 "io/ioutil" 25 "os" 26 "strings" 27 28 "github.com/hyperledger/fabric/bccsp/factory" 29 "github.com/hyperledger/fabric/common/config" 30 mspconfig "github.com/hyperledger/fabric/common/config/msp" 31 "github.com/hyperledger/fabric/common/configtx" 32 "github.com/hyperledger/fabric/common/configtx/tool/configtxgen/metadata" 33 genesisconfig "github.com/hyperledger/fabric/common/configtx/tool/localconfig" 34 "github.com/hyperledger/fabric/common/configtx/tool/provisional" 35 "github.com/hyperledger/fabric/common/flogging" 36 cb "github.com/hyperledger/fabric/protos/common" 37 pb "github.com/hyperledger/fabric/protos/peer" 38 "github.com/hyperledger/fabric/protos/utils" 39 40 "github.com/golang/protobuf/proto" 41 logging "github.com/op/go-logging" 42 ) 43 44 var exitCode = 0 45 46 var logger = flogging.MustGetLogger("common/configtx/tool") 47 48 func doOutputBlock(config *genesisconfig.Profile, channelID string, outputBlock string) error { 49 pgen := provisional.New(config) 50 logger.Info("Generating genesis block") 51 if config.Orderer == nil { 52 return fmt.Errorf("config does not contain an Orderers section, necessary for all config blocks, aborting") 53 } 54 if config.Consortiums == nil { 55 logger.Warning("Genesis block does not contain a consortiums group definition. This block cannot be used for orderer bootstrap.") 56 } 57 genesisBlock := pgen.GenesisBlockForChannel(channelID) 58 logger.Info("Writing genesis block") 59 err := ioutil.WriteFile(outputBlock, utils.MarshalOrPanic(genesisBlock), 0644) 60 if err != nil { 61 return fmt.Errorf("Error writing genesis block: %s", err) 62 } 63 return nil 64 } 65 66 func doOutputChannelCreateTx(conf *genesisconfig.Profile, channelID string, outputChannelCreateTx string) error { 67 logger.Info("Generating new channel configtx") 68 69 if conf.Application == nil { 70 return fmt.Errorf("Cannot define a new channel with no Application section") 71 } 72 73 if conf.Consortium == "" { 74 return fmt.Errorf("Cannot define a new channel with no Consortium value") 75 } 76 77 // XXX we ignore the non-application org names here, once the tool supports configuration updates 78 // we should come up with a cleaner way to handle this, but leaving as is for the moment to not break 79 // backwards compatibility 80 var orgNames []string 81 for _, org := range conf.Application.Organizations { 82 orgNames = append(orgNames, org.Name) 83 } 84 configtx, err := configtx.MakeChainCreationTransaction(channelID, conf.Consortium, nil, orgNames...) 85 if err != nil { 86 return fmt.Errorf("Error generating configtx: %s", err) 87 } 88 logger.Info("Writing new channel tx") 89 err = ioutil.WriteFile(outputChannelCreateTx, utils.MarshalOrPanic(configtx), 0644) 90 if err != nil { 91 return fmt.Errorf("Error writing channel create tx: %s", err) 92 } 93 return nil 94 } 95 96 func doOutputAnchorPeersUpdate(conf *genesisconfig.Profile, channelID string, outputAnchorPeersUpdate string, asOrg string) error { 97 logger.Info("Generating anchor peer update") 98 if asOrg == "" { 99 return fmt.Errorf("Must specify an organization to update the anchor peer for") 100 } 101 102 if conf.Application == nil { 103 return fmt.Errorf("Cannot update anchor peers without an application section") 104 } 105 106 var org *genesisconfig.Organization 107 for _, iorg := range conf.Application.Organizations { 108 if iorg.Name == asOrg { 109 org = iorg 110 } 111 } 112 113 if org == nil { 114 return fmt.Errorf("No organization name matching: %s", asOrg) 115 } 116 117 anchorPeers := make([]*pb.AnchorPeer, len(org.AnchorPeers)) 118 for i, anchorPeer := range org.AnchorPeers { 119 anchorPeers[i] = &pb.AnchorPeer{ 120 Host: anchorPeer.Host, 121 Port: int32(anchorPeer.Port), 122 } 123 } 124 125 configGroup := config.TemplateAnchorPeers(org.Name, anchorPeers) 126 configGroup.Groups[config.ApplicationGroupKey].Groups[org.Name].Values[config.AnchorPeersKey].ModPolicy = mspconfig.AdminsPolicyKey 127 configUpdate := &cb.ConfigUpdate{ 128 ChannelId: channelID, 129 WriteSet: configGroup, 130 ReadSet: cb.NewConfigGroup(), 131 } 132 133 // Add all the existing config to the readset 134 configUpdate.ReadSet.Groups[config.ApplicationGroupKey] = cb.NewConfigGroup() 135 configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Version = 1 136 configUpdate.ReadSet.Groups[config.ApplicationGroupKey].ModPolicy = mspconfig.AdminsPolicyKey 137 configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name] = cb.NewConfigGroup() 138 configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Values[config.MSPKey] = &cb.ConfigValue{} 139 configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.ReadersPolicyKey] = &cb.ConfigPolicy{} 140 configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.WritersPolicyKey] = &cb.ConfigPolicy{} 141 configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.AdminsPolicyKey] = &cb.ConfigPolicy{} 142 143 // Add all the existing at the same versions to the writeset 144 configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Version = 1 145 configUpdate.WriteSet.Groups[config.ApplicationGroupKey].ModPolicy = mspconfig.AdminsPolicyKey 146 configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Version = 1 147 configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].ModPolicy = mspconfig.AdminsPolicyKey 148 configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Values[config.MSPKey] = &cb.ConfigValue{} 149 configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.ReadersPolicyKey] = &cb.ConfigPolicy{} 150 configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.WritersPolicyKey] = &cb.ConfigPolicy{} 151 configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.AdminsPolicyKey] = &cb.ConfigPolicy{} 152 153 configUpdateEnvelope := &cb.ConfigUpdateEnvelope{ 154 ConfigUpdate: utils.MarshalOrPanic(configUpdate), 155 } 156 157 update := &cb.Envelope{ 158 Payload: utils.MarshalOrPanic(&cb.Payload{ 159 Header: &cb.Header{ 160 ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{ 161 ChannelId: channelID, 162 Type: int32(cb.HeaderType_CONFIG_UPDATE), 163 }), 164 }, 165 Data: utils.MarshalOrPanic(configUpdateEnvelope), 166 }), 167 } 168 169 logger.Info("Writing anchor peer update") 170 err := ioutil.WriteFile(outputAnchorPeersUpdate, utils.MarshalOrPanic(update), 0644) 171 if err != nil { 172 return fmt.Errorf("Error writing channel anchor peer update: %s", err) 173 } 174 return nil 175 } 176 177 func doInspectBlock(inspectBlock string) error { 178 logger.Info("Inspecting block") 179 data, err := ioutil.ReadFile(inspectBlock) 180 if err != nil { 181 return fmt.Errorf("Could not read block %s", inspectBlock) 182 } 183 184 logger.Info("Parsing genesis block") 185 block := &cb.Block{} 186 err = proto.Unmarshal(data, block) 187 if err != nil { 188 return fmt.Errorf("Error unmarshaling block: %s", err) 189 } 190 191 ctx, err := utils.ExtractEnvelope(block, 0) 192 if err != nil { 193 return fmt.Errorf("Error retrieving configtx from block: %s", err) 194 } 195 196 payload, err := utils.UnmarshalPayload(ctx.Payload) 197 if err != nil { 198 return fmt.Errorf("Error extracting configtx payload: %s", err) 199 } 200 201 if payload.Header == nil { 202 return fmt.Errorf("Config block did not contain header") 203 } 204 205 header, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader) 206 if err != nil { 207 return fmt.Errorf("Error unmarshaling channel header: %s", err) 208 } 209 210 if header.Type != int32(cb.HeaderType_CONFIG) { 211 return fmt.Errorf("Bad header type: %d", header.Type) 212 } 213 214 configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data) 215 if err != nil { 216 return fmt.Errorf("Bad configuration envelope") 217 } 218 219 if configEnvelope.Config == nil { 220 return fmt.Errorf("ConfigEnvelope contained no config") 221 } 222 223 configAsJSON, err := configGroupAsJSON(configEnvelope.Config.ChannelGroup) 224 if err != nil { 225 return err 226 } 227 228 fmt.Printf("Config for channel: %s at sequence %d\n", header.ChannelId, configEnvelope.Config.Sequence) 229 fmt.Println(configAsJSON) 230 231 return nil 232 } 233 234 func configGroupAsJSON(group *cb.ConfigGroup) (string, error) { 235 configResult, err := configtx.NewConfigResult(group, configtx.NewInitializer()) 236 if err != nil { 237 return "", fmt.Errorf("Error parsing config: %s", err) 238 } 239 240 buffer := &bytes.Buffer{} 241 err = json.Indent(buffer, []byte(configResult.JSON()), "", " ") 242 if err != nil { 243 return "", fmt.Errorf("Error in output JSON (usually a programming bug): %s", err) 244 } 245 return buffer.String(), nil 246 } 247 248 func doInspectChannelCreateTx(inspectChannelCreateTx string) error { 249 logger.Info("Inspecting transaction") 250 data, err := ioutil.ReadFile(inspectChannelCreateTx) 251 if err != nil { 252 return fmt.Errorf("could not read channel create tx: %s", err) 253 } 254 255 logger.Info("Parsing transaction") 256 env, err := utils.UnmarshalEnvelope(data) 257 if err != nil { 258 return fmt.Errorf("Error unmarshaling envelope: %s", err) 259 } 260 261 payload, err := utils.UnmarshalPayload(env.Payload) 262 if err != nil { 263 return fmt.Errorf("Error extracting configtx payload: %s", err) 264 } 265 266 if payload.Header == nil { 267 return fmt.Errorf("Config block did not contain header") 268 } 269 270 header, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader) 271 if err != nil { 272 return fmt.Errorf("Error unmarshaling channel header: %s", err) 273 } 274 275 if header.Type != int32(cb.HeaderType_CONFIG_UPDATE) { 276 return fmt.Errorf("Bad header type: %d", header.Type) 277 } 278 279 configUpdateEnvelope, err := configtx.UnmarshalConfigUpdateEnvelope(payload.Data) 280 if err != nil { 281 return fmt.Errorf("Bad ConfigUpdateEnvelope") 282 } 283 284 configUpdate, err := configtx.UnmarshalConfigUpdate(configUpdateEnvelope.ConfigUpdate) 285 if err != nil { 286 return fmt.Errorf("ConfigUpdateEnvelope contained no config") 287 } 288 289 if configUpdate.ChannelId != header.ChannelId { 290 return fmt.Errorf("ConfigUpdateEnvelope was for different channel than envelope: %s vs %s", configUpdate.ChannelId, header.ChannelId) 291 } 292 293 fmt.Printf("\nChannel creation for channel: %s\n", header.ChannelId) 294 fmt.Println() 295 296 if configUpdate.ReadSet == nil { 297 fmt.Println("Read Set: empty") 298 } else { 299 fmt.Println("Read Set:") 300 readSetAsJSON, err := configGroupAsJSON(configUpdate.ReadSet) 301 if err != nil { 302 return err 303 } 304 fmt.Println(readSetAsJSON) 305 } 306 fmt.Println() 307 308 if configUpdate.WriteSet == nil { 309 return fmt.Errorf("Empty WriteSet") 310 } 311 312 fmt.Println("Write Set:") 313 writeSetAsJSON, err := configGroupAsJSON(configUpdate.WriteSet) 314 if err != nil { 315 return err 316 } 317 fmt.Println(writeSetAsJSON) 318 fmt.Println() 319 320 readSetMap, err := configtx.MapConfig(configUpdate.ReadSet) 321 if err != nil { 322 return fmt.Errorf("Error mapping read set: %s", err) 323 } 324 writeSetMap, err := configtx.MapConfig(configUpdate.WriteSet) 325 if err != nil { 326 return fmt.Errorf("Error mapping write set: %s", err) 327 } 328 329 fmt.Println("Delta Set:") 330 deltaSet := configtx.ComputeDeltaSet(readSetMap, writeSetMap) 331 for key := range deltaSet { 332 fmt.Println(key) 333 } 334 fmt.Println() 335 336 return nil 337 } 338 339 func main() { 340 var outputBlock, outputChannelCreateTx, profile, channelID, inspectBlock, inspectChannelCreateTx, outputAnchorPeersUpdate, asOrg string 341 342 flag.StringVar(&outputBlock, "outputBlock", "", "The path to write the genesis block to (if set)") 343 flag.StringVar(&channelID, "channelID", provisional.TestChainID, "The channel ID to use in the configtx") 344 flag.StringVar(&outputChannelCreateTx, "outputCreateChannelTx", "", "The path to write a channel creation configtx to (if set)") 345 flag.StringVar(&profile, "profile", genesisconfig.SampleInsecureProfile, "The profile from configtx.yaml to use for generation.") 346 flag.StringVar(&inspectBlock, "inspectBlock", "", "Prints the configuration contained in the block at the specified path") 347 flag.StringVar(&inspectChannelCreateTx, "inspectChannelCreateTx", "", "Prints the configuration contained in the transaction at the specified path") 348 flag.StringVar(&outputAnchorPeersUpdate, "outputAnchorPeersUpdate", "", "Creates an config update to update an anchor peer (works only with the default channel creation, and only for the first update)") 349 flag.StringVar(&asOrg, "asOrg", "", "Performs the config generation as a particular organization (by name), only including values in the write set that org (likely) has privilege to set") 350 351 version := flag.Bool("version", false, "Show version information") 352 353 flag.Parse() 354 355 // show version 356 if *version { 357 printVersion() 358 os.Exit(exitCode) 359 } 360 361 logging.SetLevel(logging.INFO, "") 362 363 // don't need to panic when running via command line 364 defer func() { 365 if err := recover(); err != nil { 366 if strings.Contains(fmt.Sprint(err), "Error reading configuration: Unsupported Config Type") { 367 logger.Error("Could not find configtx.yaml. " + 368 "Please make sure that FABRIC_CFG_PATH is set to a path " + 369 "which contains configtx.yaml") 370 } 371 os.Exit(1) 372 } 373 }() 374 375 logger.Info("Loading configuration") 376 factory.InitFactories(nil) 377 config := genesisconfig.Load(profile) 378 379 if outputBlock != "" { 380 if err := doOutputBlock(config, channelID, outputBlock); err != nil { 381 logger.Fatalf("Error on outputBlock: %s", err) 382 } 383 } 384 385 if outputChannelCreateTx != "" { 386 if err := doOutputChannelCreateTx(config, channelID, outputChannelCreateTx); err != nil { 387 logger.Fatalf("Error on outputChannelCreateTx: %s", err) 388 } 389 } 390 391 if inspectBlock != "" { 392 if err := doInspectBlock(inspectBlock); err != nil { 393 logger.Fatalf("Error on inspectBlock: %s", err) 394 } 395 } 396 397 if inspectChannelCreateTx != "" { 398 if err := doInspectChannelCreateTx(inspectChannelCreateTx); err != nil { 399 logger.Fatalf("Error on inspectChannelCreateTx: %s", err) 400 } 401 } 402 403 if outputAnchorPeersUpdate != "" { 404 if err := doOutputAnchorPeersUpdate(config, channelID, outputAnchorPeersUpdate, asOrg); err != nil { 405 logger.Fatalf("Error on inspectChannelCreateTx: %s", err) 406 } 407 } 408 } 409 410 func printVersion() { 411 fmt.Println(metadata.GetVersionInfo()) 412 }