github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/peer/channel/create.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 channel
    18  
    19  import (
    20  	"fmt"
    21  	"io/ioutil"
    22  
    23  	"errors"
    24  
    25  	"github.com/golang/protobuf/proto"
    26  	"github.com/hyperledger/fabric/common/configtx"
    27  	genesisconfig "github.com/hyperledger/fabric/common/configtx/tool/localconfig"
    28  	localsigner "github.com/hyperledger/fabric/common/localmsp"
    29  	"github.com/hyperledger/fabric/common/util"
    30  	mspmgmt "github.com/hyperledger/fabric/msp/mgmt"
    31  	"github.com/hyperledger/fabric/peer/common"
    32  	cb "github.com/hyperledger/fabric/protos/common"
    33  	"github.com/hyperledger/fabric/protos/utils"
    34  	"github.com/spf13/cobra"
    35  )
    36  
    37  //ConfigTxFileNotFound channel create configuration tx file not found
    38  type ConfigTxFileNotFound string
    39  
    40  const createCmdDescription = "Create a channel"
    41  
    42  func (e ConfigTxFileNotFound) Error() string {
    43  	return fmt.Sprintf("channel create configuration tx file not found %s", string(e))
    44  }
    45  
    46  //InvalidCreateTx invalid channel create transaction
    47  type InvalidCreateTx string
    48  
    49  func (e InvalidCreateTx) Error() string {
    50  	return fmt.Sprintf("Invalid channel create transaction : %s", string(e))
    51  }
    52  
    53  func createCmd(cf *ChannelCmdFactory) *cobra.Command {
    54  	createCmd := &cobra.Command{
    55  		Use:   "create",
    56  		Short: createCmdDescription,
    57  		Long:  createCmdDescription,
    58  		RunE: func(cmd *cobra.Command, args []string) error {
    59  			return create(cmd, args, cf)
    60  		},
    61  	}
    62  	flagList := []string{
    63  		"channelID",
    64  		"file",
    65  		"timeout",
    66  	}
    67  	attachFlags(createCmd, flagList)
    68  
    69  	return createCmd
    70  }
    71  
    72  func createChannelFromDefaults(cf *ChannelCmdFactory) (*cb.Envelope, error) {
    73  	signer, err := mspmgmt.GetLocalMSP().GetDefaultSigningIdentity()
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  
    78  	chCrtEnv, err := configtx.MakeChainCreationTransaction(chainID, genesisconfig.SampleConsortiumName, signer)
    79  
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  
    84  	return chCrtEnv, nil
    85  }
    86  
    87  func createChannelFromConfigTx(configTxFileName string) (*cb.Envelope, error) {
    88  	cftx, err := ioutil.ReadFile(configTxFileName)
    89  	if err != nil {
    90  		return nil, ConfigTxFileNotFound(err.Error())
    91  	}
    92  
    93  	return utils.UnmarshalEnvelope(cftx)
    94  }
    95  
    96  func sanityCheckAndSignConfigTx(envConfigUpdate *cb.Envelope) (*cb.Envelope, error) {
    97  	payload, err := utils.ExtractPayload(envConfigUpdate)
    98  	if err != nil {
    99  		return nil, InvalidCreateTx("bad payload")
   100  	}
   101  
   102  	if payload.Header == nil || payload.Header.ChannelHeader == nil {
   103  		return nil, InvalidCreateTx("bad header")
   104  	}
   105  
   106  	ch, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   107  	if err != nil {
   108  		return nil, InvalidCreateTx("could not unmarshall channel header")
   109  	}
   110  
   111  	if ch.Type != int32(cb.HeaderType_CONFIG_UPDATE) {
   112  		return nil, InvalidCreateTx("bad type")
   113  	}
   114  
   115  	if ch.ChannelId == "" {
   116  		return nil, InvalidCreateTx("empty channel id")
   117  	}
   118  
   119  	if ch.ChannelId != chainID {
   120  		return nil, InvalidCreateTx(fmt.Sprintf("mismatched channel ID %s != %s", ch.ChannelId, chainID))
   121  	}
   122  
   123  	configUpdateEnv, err := configtx.UnmarshalConfigUpdateEnvelope(payload.Data)
   124  	if err != nil {
   125  		return nil, InvalidCreateTx("Bad config update env")
   126  	}
   127  
   128  	signer := localsigner.NewSigner()
   129  	sigHeader, err := signer.NewSignatureHeader()
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  
   134  	configSig := &cb.ConfigSignature{
   135  		SignatureHeader: utils.MarshalOrPanic(sigHeader),
   136  	}
   137  
   138  	configSig.Signature, err = signer.Sign(util.ConcatenateBytes(configSig.SignatureHeader, configUpdateEnv.ConfigUpdate))
   139  
   140  	configUpdateEnv.Signatures = append(configUpdateEnv.Signatures, configSig)
   141  
   142  	return utils.CreateSignedEnvelope(cb.HeaderType_CONFIG_UPDATE, chainID, signer, configUpdateEnv, 0, 0)
   143  }
   144  
   145  func sendCreateChainTransaction(cf *ChannelCmdFactory) error {
   146  	var err error
   147  	var chCrtEnv *cb.Envelope
   148  
   149  	if channelTxFile != "" {
   150  		if chCrtEnv, err = createChannelFromConfigTx(channelTxFile); err != nil {
   151  			return err
   152  		}
   153  	} else {
   154  		if chCrtEnv, err = createChannelFromDefaults(cf); err != nil {
   155  			return err
   156  		}
   157  	}
   158  
   159  	if chCrtEnv, err = sanityCheckAndSignConfigTx(chCrtEnv); err != nil {
   160  		return err
   161  	}
   162  
   163  	var broadcastClient common.BroadcastClient
   164  	broadcastClient, err = cf.BroadcastFactory()
   165  	if err != nil {
   166  		return fmt.Errorf("Error getting broadcast client: %s", err)
   167  	}
   168  
   169  	defer broadcastClient.Close()
   170  	err = broadcastClient.Send(chCrtEnv)
   171  
   172  	return err
   173  }
   174  
   175  func executeCreate(cf *ChannelCmdFactory) error {
   176  	var err error
   177  
   178  	if err = sendCreateChainTransaction(cf); err != nil {
   179  		return err
   180  	}
   181  
   182  	var block *cb.Block
   183  	if block, err = getGenesisBlock(cf); err != nil {
   184  		return err
   185  	}
   186  
   187  	b, err := proto.Marshal(block)
   188  	if err != nil {
   189  		return err
   190  	}
   191  
   192  	file := chainID + ".block"
   193  	if err = ioutil.WriteFile(file, b, 0644); err != nil {
   194  		return err
   195  	}
   196  
   197  	return nil
   198  }
   199  
   200  func create(cmd *cobra.Command, args []string, cf *ChannelCmdFactory) error {
   201  	//the global chainID filled by the "-c" command
   202  	if chainID == common.UndefinedParamValue {
   203  		return errors.New("Must supply channel ID")
   204  	}
   205  
   206  	var err error
   207  	if cf == nil {
   208  		cf, err = InitCmdFactory(EndorserNotRequired, OrdererRequired)
   209  		if err != nil {
   210  			return err
   211  		}
   212  	}
   213  	return executeCreate(cf)
   214  }