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