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 }