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  }