github.com/inklabsfoundation/inkchain@v0.17.1-0.20181025012015-c3cef8062f19/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/inklabsfoundation/inkchain/common/configtx"
    27  	genesisconfig "github.com/inklabsfoundation/inkchain/common/configtx/tool/localconfig"
    28  	localsigner "github.com/inklabsfoundation/inkchain/common/localmsp"
    29  	"github.com/inklabsfoundation/inkchain/common/util"
    30  	mspmgmt "github.com/inklabsfoundation/inkchain/msp/mgmt"
    31  	"github.com/inklabsfoundation/inkchain/peer/common"
    32  	cb "github.com/inklabsfoundation/inkchain/protos/common"
    33  	"github.com/inklabsfoundation/inkchain/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      // Specifying the chainID on the CLI is usually redundant, as a hack, set it
   120      // here if it has not been set explicitly
   121      if chainID == "" {
   122              chainID = ch.ChannelId
   123      }
   124  
   125  	if ch.ChannelId != chainID {
   126  		return nil, InvalidCreateTx(fmt.Sprintf("mismatched channel ID %s != %s", ch.ChannelId, chainID))
   127  	}
   128  
   129  	configUpdateEnv, err := configtx.UnmarshalConfigUpdateEnvelope(payload.Data)
   130  	if err != nil {
   131  		return nil, InvalidCreateTx("Bad config update env")
   132  	}
   133  
   134  	signer := localsigner.NewSigner()
   135  	sigHeader, err := signer.NewSignatureHeader()
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  
   140  	configSig := &cb.ConfigSignature{
   141  		SignatureHeader: utils.MarshalOrPanic(sigHeader),
   142  	}
   143  
   144  	configSig.Signature, err = signer.Sign(util.ConcatenateBytes(configSig.SignatureHeader, configUpdateEnv.ConfigUpdate))
   145  
   146  	configUpdateEnv.Signatures = append(configUpdateEnv.Signatures, configSig)
   147  
   148  	return utils.CreateSignedEnvelope(cb.HeaderType_CONFIG_UPDATE, chainID, signer, configUpdateEnv, 0, 0)
   149  }
   150  
   151  func sendCreateChainTransaction(cf *ChannelCmdFactory) error {
   152  	var err error
   153  	var chCrtEnv *cb.Envelope
   154  
   155  	if channelTxFile != "" {
   156  		if chCrtEnv, err = createChannelFromConfigTx(channelTxFile); err != nil {
   157  			return err
   158  		}
   159  	} else {
   160  		if chCrtEnv, err = createChannelFromDefaults(cf); err != nil {
   161  			return err
   162  		}
   163  	}
   164  
   165  	if chCrtEnv, err = sanityCheckAndSignConfigTx(chCrtEnv); err != nil {
   166  		return err
   167  	}
   168  
   169  	var broadcastClient common.BroadcastClient
   170  	broadcastClient, err = cf.BroadcastFactory()
   171  	if err != nil {
   172  		return fmt.Errorf("Error getting broadcast client: %s", err)
   173  	}
   174  
   175  	defer broadcastClient.Close()
   176  	err = broadcastClient.Send(chCrtEnv)
   177  
   178  	return err
   179  }
   180  
   181  func executeCreate(cf *ChannelCmdFactory) error {
   182  	var err error
   183  
   184  	if err = sendCreateChainTransaction(cf); err != nil {
   185  		return err
   186  	}
   187  
   188  	var block *cb.Block
   189  	if block, err = getGenesisBlock(cf); err != nil {
   190  		return err
   191  	}
   192  
   193  	b, err := proto.Marshal(block)
   194  	if err != nil {
   195  		return err
   196  	}
   197  
   198  	file := chainID + ".block"
   199  	if err = ioutil.WriteFile(file, b, 0644); err != nil {
   200  		return err
   201  	}
   202  
   203  	return nil
   204  }
   205  
   206  func create(cmd *cobra.Command, args []string, cf *ChannelCmdFactory) error {
   207  	//the global chainID filled by the "-c" command
   208  	if chainID == common.UndefinedParamValue {
   209  		return errors.New("Must supply channel ID")
   210  	}
   211  
   212  	var err error
   213  	if cf == nil {
   214  		cf, err = InitCmdFactory(EndorserNotRequired, OrdererRequired)
   215  		if err != nil {
   216  			return err
   217  		}
   218  	}
   219  	return executeCreate(cf)
   220  }