github.com/ewagmig/fabric@v2.1.1+incompatible/cmd/configtxgen/main.go (about) 1 /* 2 Copyright IBM Corp. 2017 All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package main 8 9 import ( 10 "flag" 11 "fmt" 12 "io/ioutil" 13 "os" 14 "path/filepath" 15 "strings" 16 17 "github.com/golang/protobuf/proto" 18 cb "github.com/hyperledger/fabric-protos-go/common" 19 "github.com/hyperledger/fabric/bccsp/factory" 20 "github.com/hyperledger/fabric/common/channelconfig" 21 "github.com/hyperledger/fabric/common/flogging" 22 "github.com/hyperledger/fabric/common/tools/protolator" 23 "github.com/hyperledger/fabric/common/tools/protolator/protoext/ordererext" 24 "github.com/hyperledger/fabric/internal/configtxgen/encoder" 25 "github.com/hyperledger/fabric/internal/configtxgen/genesisconfig" 26 "github.com/hyperledger/fabric/internal/configtxgen/metadata" 27 "github.com/hyperledger/fabric/internal/configtxlator/update" 28 "github.com/hyperledger/fabric/protoutil" 29 "github.com/pkg/errors" 30 ) 31 32 var logger = flogging.MustGetLogger("common.tools.configtxgen") 33 34 func doOutputBlock(config *genesisconfig.Profile, channelID string, outputBlock string) error { 35 pgen, err := encoder.NewBootstrapper(config) 36 if err != nil { 37 return errors.WithMessage(err, "could not create bootstrapper") 38 } 39 logger.Info("Generating genesis block") 40 if config.Orderer == nil { 41 return errors.Errorf("refusing to generate block which is missing orderer section") 42 } 43 if config.Consortiums == nil { 44 logger.Warning("Genesis block does not contain a consortiums group definition. This block cannot be used for orderer bootstrap.") 45 } 46 genesisBlock := pgen.GenesisBlockForChannel(channelID) 47 logger.Info("Writing genesis block") 48 err = writeFile(outputBlock, protoutil.MarshalOrPanic(genesisBlock), 0640) 49 if err != nil { 50 return fmt.Errorf("Error writing genesis block: %s", err) 51 } 52 return nil 53 } 54 55 func doOutputChannelCreateTx(conf, baseProfile *genesisconfig.Profile, channelID string, outputChannelCreateTx string) error { 56 logger.Info("Generating new channel configtx") 57 58 var configtx *cb.Envelope 59 var err error 60 if baseProfile == nil { 61 configtx, err = encoder.MakeChannelCreationTransaction(channelID, nil, conf) 62 } else { 63 configtx, err = encoder.MakeChannelCreationTransactionWithSystemChannelContext(channelID, nil, conf, baseProfile) 64 } 65 if err != nil { 66 return err 67 } 68 69 logger.Info("Writing new channel tx") 70 err = writeFile(outputChannelCreateTx, protoutil.MarshalOrPanic(configtx), 0640) 71 if err != nil { 72 return fmt.Errorf("Error writing channel create tx: %s", err) 73 } 74 return nil 75 } 76 77 func doOutputAnchorPeersUpdate(conf *genesisconfig.Profile, channelID string, outputAnchorPeersUpdate string, asOrg string) error { 78 logger.Info("Generating anchor peer update") 79 if asOrg == "" { 80 return fmt.Errorf("Must specify an organization to update the anchor peer for") 81 } 82 83 if conf.Application == nil { 84 return fmt.Errorf("Cannot update anchor peers without an application section") 85 } 86 87 original, err := encoder.NewChannelGroup(conf) 88 if err != nil { 89 return errors.WithMessage(err, "error parsing profile as channel group") 90 } 91 original.Groups[channelconfig.ApplicationGroupKey].Version = 1 92 93 updated := proto.Clone(original).(*cb.ConfigGroup) 94 95 originalOrg, ok := original.Groups[channelconfig.ApplicationGroupKey].Groups[asOrg] 96 if !ok { 97 return errors.Errorf("org with name '%s' does not exist in config", asOrg) 98 } 99 100 if _, ok = originalOrg.Values[channelconfig.AnchorPeersKey]; !ok { 101 return errors.Errorf("org '%s' does not have any anchor peers defined", asOrg) 102 } 103 104 delete(originalOrg.Values, channelconfig.AnchorPeersKey) 105 106 updt, err := update.Compute(&cb.Config{ChannelGroup: original}, &cb.Config{ChannelGroup: updated}) 107 if err != nil { 108 return errors.WithMessage(err, "could not compute update") 109 } 110 updt.ChannelId = channelID 111 112 newConfigUpdateEnv := &cb.ConfigUpdateEnvelope{ 113 ConfigUpdate: protoutil.MarshalOrPanic(updt), 114 } 115 116 updateTx, err := protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG_UPDATE, channelID, nil, newConfigUpdateEnv, 0, 0) 117 118 logger.Info("Writing anchor peer update") 119 err = writeFile(outputAnchorPeersUpdate, protoutil.MarshalOrPanic(updateTx), 0640) 120 if err != nil { 121 return fmt.Errorf("Error writing channel anchor peer update: %s", err) 122 } 123 return nil 124 } 125 126 func doInspectBlock(inspectBlock string) error { 127 logger.Info("Inspecting block") 128 data, err := ioutil.ReadFile(inspectBlock) 129 if err != nil { 130 return fmt.Errorf("Could not read block %s", inspectBlock) 131 } 132 133 logger.Info("Parsing genesis block") 134 block, err := protoutil.UnmarshalBlock(data) 135 if err != nil { 136 return fmt.Errorf("error unmarshaling to block: %s", err) 137 } 138 err = protolator.DeepMarshalJSON(os.Stdout, block) 139 if err != nil { 140 return fmt.Errorf("malformed block contents: %s", err) 141 } 142 return nil 143 } 144 145 func doInspectChannelCreateTx(inspectChannelCreateTx string) error { 146 logger.Info("Inspecting transaction") 147 data, err := ioutil.ReadFile(inspectChannelCreateTx) 148 if err != nil { 149 return fmt.Errorf("could not read channel create tx: %s", err) 150 } 151 152 logger.Info("Parsing transaction") 153 env, err := protoutil.UnmarshalEnvelope(data) 154 if err != nil { 155 return fmt.Errorf("Error unmarshaling envelope: %s", err) 156 } 157 158 err = protolator.DeepMarshalJSON(os.Stdout, env) 159 if err != nil { 160 return fmt.Errorf("malformed transaction contents: %s", err) 161 } 162 163 return nil 164 } 165 166 func doPrintOrg(t *genesisconfig.TopLevel, printOrg string) error { 167 for _, org := range t.Organizations { 168 if org.Name == printOrg { 169 og, err := encoder.NewOrdererOrgGroup(org) 170 if err != nil { 171 return errors.Wrapf(err, "bad org definition for org %s", org.Name) 172 } 173 174 if err := protolator.DeepMarshalJSON(os.Stdout, &ordererext.DynamicOrdererOrgGroup{ConfigGroup: og}); err != nil { 175 return errors.Wrapf(err, "malformed org definition for org: %s", org.Name) 176 } 177 return nil 178 } 179 } 180 return errors.Errorf("organization %s not found", printOrg) 181 } 182 183 func writeFile(filename string, data []byte, perm os.FileMode) error { 184 dirPath := filepath.Dir(filename) 185 exists, err := dirExists(dirPath) 186 if err != nil { 187 return err 188 } 189 if !exists { 190 err = os.MkdirAll(dirPath, 0750) 191 if err != nil { 192 return err 193 } 194 } 195 return ioutil.WriteFile(filename, data, perm) 196 } 197 198 func dirExists(path string) (bool, error) { 199 _, err := os.Stat(path) 200 if err == nil { 201 return true, nil 202 } 203 if os.IsNotExist(err) { 204 return false, nil 205 } 206 return false, err 207 } 208 209 func main() { 210 var outputBlock, outputChannelCreateTx, channelCreateTxBaseProfile, profile, configPath, channelID, inspectBlock, inspectChannelCreateTx, outputAnchorPeersUpdate, asOrg, printOrg string 211 212 flag.StringVar(&outputBlock, "outputBlock", "", "The path to write the genesis block to (if set)") 213 flag.StringVar(&channelID, "channelID", "", "The channel ID to use in the configtx") 214 flag.StringVar(&outputChannelCreateTx, "outputCreateChannelTx", "", "The path to write a channel creation configtx to (if set)") 215 flag.StringVar(&channelCreateTxBaseProfile, "channelCreateTxBaseProfile", "", "Specifies a profile to consider as the orderer system channel current state to allow modification of non-application parameters during channel create tx generation. Only valid in conjunction with 'outputCreateChannelTx'.") 216 flag.StringVar(&profile, "profile", "", "The profile from configtx.yaml to use for generation.") 217 flag.StringVar(&configPath, "configPath", "", "The path containing the configuration to use (if set)") 218 flag.StringVar(&inspectBlock, "inspectBlock", "", "Prints the configuration contained in the block at the specified path") 219 flag.StringVar(&inspectChannelCreateTx, "inspectChannelCreateTx", "", "Prints the configuration contained in the transaction at the specified path") 220 flag.StringVar(&outputAnchorPeersUpdate, "outputAnchorPeersUpdate", "", "[DEPRECATED] Creates a config update to update an anchor peer (works only with the default channel creation, and only for the first update)") 221 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") 222 flag.StringVar(&printOrg, "printOrg", "", "Prints the definition of an organization as JSON. (useful for adding an org to a channel manually)") 223 224 version := flag.Bool("version", false, "Show version information") 225 226 flag.Parse() 227 228 if channelID == "" && (outputBlock != "" || outputChannelCreateTx != "" || outputAnchorPeersUpdate != "") { 229 logger.Fatalf("Missing channelID, please specify it with '-channelID'") 230 } 231 232 // show version 233 if *version { 234 printVersion() 235 os.Exit(0) 236 } 237 238 // don't need to panic when running via command line 239 defer func() { 240 if err := recover(); err != nil { 241 if strings.Contains(fmt.Sprint(err), "Error reading configuration: Unsupported Config Type") { 242 logger.Error("Could not find configtx.yaml. " + 243 "Please make sure that FABRIC_CFG_PATH or -configPath is set to a path " + 244 "which contains configtx.yaml") 245 os.Exit(1) 246 } 247 if strings.Contains(fmt.Sprint(err), "Could not find profile") { 248 logger.Error(fmt.Sprint(err) + ". " + 249 "Please make sure that FABRIC_CFG_PATH or -configPath is set to a path " + 250 "which contains configtx.yaml with the specified profile") 251 os.Exit(1) 252 } 253 logger.Panic(err) 254 } 255 }() 256 257 logger.Info("Loading configuration") 258 factory.InitFactories(nil) 259 var profileConfig *genesisconfig.Profile 260 if outputBlock != "" || outputChannelCreateTx != "" || outputAnchorPeersUpdate != "" { 261 if profile == "" { 262 logger.Fatalf("The '-profile' is required when '-outputBlock', '-outputChannelCreateTx', or '-outputAnchorPeersUpdate' is specified") 263 } 264 265 if configPath != "" { 266 profileConfig = genesisconfig.Load(profile, configPath) 267 } else { 268 profileConfig = genesisconfig.Load(profile) 269 } 270 } 271 272 var baseProfile *genesisconfig.Profile 273 if channelCreateTxBaseProfile != "" { 274 if outputChannelCreateTx == "" { 275 logger.Warning("Specified 'channelCreateTxBaseProfile', but did not specify 'outputChannelCreateTx', 'channelCreateTxBaseProfile' will not affect output.") 276 } 277 if configPath != "" { 278 baseProfile = genesisconfig.Load(channelCreateTxBaseProfile, configPath) 279 } else { 280 baseProfile = genesisconfig.Load(channelCreateTxBaseProfile) 281 } 282 } 283 284 if outputBlock != "" { 285 if err := doOutputBlock(profileConfig, channelID, outputBlock); err != nil { 286 logger.Fatalf("Error on outputBlock: %s", err) 287 } 288 } 289 290 if outputChannelCreateTx != "" { 291 if err := doOutputChannelCreateTx(profileConfig, baseProfile, channelID, outputChannelCreateTx); err != nil { 292 logger.Fatalf("Error on outputChannelCreateTx: %s", err) 293 } 294 } 295 296 if inspectBlock != "" { 297 if err := doInspectBlock(inspectBlock); err != nil { 298 logger.Fatalf("Error on inspectBlock: %s", err) 299 } 300 } 301 302 if inspectChannelCreateTx != "" { 303 if err := doInspectChannelCreateTx(inspectChannelCreateTx); err != nil { 304 logger.Fatalf("Error on inspectChannelCreateTx: %s", err) 305 } 306 } 307 308 if outputAnchorPeersUpdate != "" { 309 if err := doOutputAnchorPeersUpdate(profileConfig, channelID, outputAnchorPeersUpdate, asOrg); err != nil { 310 logger.Fatalf("Error on inspectChannelCreateTx: %s", err) 311 } 312 } 313 314 if printOrg != "" { 315 var topLevelConfig *genesisconfig.TopLevel 316 if configPath != "" { 317 topLevelConfig = genesisconfig.LoadTopLevel(configPath) 318 } else { 319 topLevelConfig = genesisconfig.LoadTopLevel() 320 } 321 322 if err := doPrintOrg(topLevelConfig, printOrg); err != nil { 323 logger.Fatalf("Error on printOrg: %s", err) 324 } 325 } 326 } 327 328 func printVersion() { 329 fmt.Println(metadata.GetVersionInfo()) 330 }