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  }