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