github.com/kchristidis/fabric@v1.0.4-0.20171028114726-837acd08cde1/peer/chaincode/common.go (about) 1 /* 2 Copyright IBM Corp. 2016 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 chaincode 18 19 import ( 20 "encoding/json" 21 "errors" 22 "fmt" 23 "os" 24 "strings" 25 26 "github.com/hyperledger/fabric/common/cauthdsl" 27 "github.com/hyperledger/fabric/core/chaincode" 28 "github.com/hyperledger/fabric/core/chaincode/platforms" 29 "github.com/hyperledger/fabric/core/chaincode/shim" 30 "github.com/hyperledger/fabric/core/container" 31 "github.com/hyperledger/fabric/msp" 32 "github.com/hyperledger/fabric/peer/common" 33 pcommon "github.com/hyperledger/fabric/protos/common" 34 pb "github.com/hyperledger/fabric/protos/peer" 35 putils "github.com/hyperledger/fabric/protos/utils" 36 "github.com/spf13/cobra" 37 "golang.org/x/net/context" 38 ) 39 40 // checkSpec to see if chaincode resides within current package capture for language. 41 func checkSpec(spec *pb.ChaincodeSpec) error { 42 // Don't allow nil value 43 if spec == nil { 44 return errors.New("Expected chaincode specification, nil received") 45 } 46 47 platform, err := platforms.Find(spec.Type) 48 if err != nil { 49 return fmt.Errorf("Failed to determine platform type: %s", err) 50 } 51 52 return platform.ValidateSpec(spec) 53 } 54 55 // getChaincodeDeploymentSpec get chaincode deployment spec given the chaincode spec 56 func getChaincodeDeploymentSpec(spec *pb.ChaincodeSpec, crtPkg bool) (*pb.ChaincodeDeploymentSpec, error) { 57 var codePackageBytes []byte 58 if chaincode.IsDevMode() == false && crtPkg { 59 var err error 60 if err = checkSpec(spec); err != nil { 61 return nil, err 62 } 63 64 codePackageBytes, err = container.GetChaincodePackageBytes(spec) 65 if err != nil { 66 err = fmt.Errorf("Error getting chaincode package bytes: %s", err) 67 return nil, err 68 } 69 } 70 chaincodeDeploymentSpec := &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: codePackageBytes} 71 return chaincodeDeploymentSpec, nil 72 } 73 74 // getChaincodeSpec get chaincode spec from the cli cmd pramameters 75 func getChaincodeSpec(cmd *cobra.Command) (*pb.ChaincodeSpec, error) { 76 spec := &pb.ChaincodeSpec{} 77 if err := checkChaincodeCmdParams(cmd); err != nil { 78 return spec, err 79 } 80 81 // Build the spec 82 input := &pb.ChaincodeInput{} 83 if err := json.Unmarshal([]byte(chaincodeCtorJSON), &input); err != nil { 84 return spec, fmt.Errorf("Chaincode argument error: %s", err) 85 } 86 87 chaincodeLang = strings.ToUpper(chaincodeLang) 88 if pb.ChaincodeSpec_Type_value[chaincodeLang] == int32(pb.ChaincodeSpec_JAVA) { 89 return nil, fmt.Errorf("Java chaincode is work-in-progress and disabled") 90 } 91 spec = &pb.ChaincodeSpec{ 92 Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value[chaincodeLang]), 93 ChaincodeId: &pb.ChaincodeID{Path: chaincodePath, Name: chaincodeName, Version: chaincodeVersion}, 94 Input: input, 95 } 96 return spec, nil 97 } 98 99 func chaincodeInvokeOrQuery(cmd *cobra.Command, args []string, invoke bool, cf *ChaincodeCmdFactory) (err error) { 100 spec, err := getChaincodeSpec(cmd) 101 if err != nil { 102 return err 103 } 104 105 proposalResp, err := ChaincodeInvokeOrQuery( 106 spec, 107 chainID, 108 invoke, 109 cf.Signer, 110 cf.EndorserClient, 111 cf.BroadcastClient) 112 113 if err != nil { 114 return fmt.Errorf("%s - %v", err, proposalResp) 115 } 116 117 if invoke { 118 if proposalResp.Response.Status >= shim.ERROR { 119 logger.Debugf("ESCC invoke result: %v", proposalResp) 120 pRespPayload, err := putils.GetProposalResponsePayload(proposalResp.Payload) 121 if err != nil { 122 return fmt.Errorf("Error while unmarshaling proposal response payload: %s", err) 123 } 124 ca, err := putils.GetChaincodeAction(pRespPayload.Extension) 125 if err != nil { 126 return fmt.Errorf("Error while unmarshaling chaincode action: %s", err) 127 } 128 logger.Warningf("Endorsement failure during invoke. chaincode result: %v", ca.Response) 129 } else { 130 logger.Debugf("ESCC invoke result: %v", proposalResp) 131 pRespPayload, err := putils.GetProposalResponsePayload(proposalResp.Payload) 132 if err != nil { 133 return fmt.Errorf("Error while unmarshaling proposal response payload: %s", err) 134 } 135 ca, err := putils.GetChaincodeAction(pRespPayload.Extension) 136 if err != nil { 137 return fmt.Errorf("Error while unmarshaling chaincode action: %s", err) 138 } 139 logger.Infof("Chaincode invoke successful. result: %v", ca.Response) 140 } 141 } else { 142 if proposalResp == nil { 143 return fmt.Errorf("Error query %s by endorsing: %s", chainFuncName, err) 144 } 145 146 if chaincodeQueryRaw { 147 if chaincodeQueryHex { 148 return fmt.Errorf("Options --raw (-r) and --hex (-x) are not compatible") 149 } 150 fmt.Print("Query Result (Raw): ") 151 os.Stdout.Write(proposalResp.Response.Payload) 152 } else { 153 if chaincodeQueryHex { 154 fmt.Printf("Query Result: %x\n", proposalResp.Response.Payload) 155 } else { 156 fmt.Printf("Query Result: %s\n", string(proposalResp.Response.Payload)) 157 } 158 } 159 } 160 return nil 161 } 162 163 func checkChaincodeCmdParams(cmd *cobra.Command) error { 164 //we need chaincode name for everything, including deploy 165 if chaincodeName == common.UndefinedParamValue { 166 return fmt.Errorf("Must supply value for %s name parameter.", chainFuncName) 167 } 168 169 if cmd.Name() == instantiateCmdName || cmd.Name() == installCmdName || 170 cmd.Name() == upgradeCmdName || cmd.Name() == packageCmdName { 171 if chaincodeVersion == common.UndefinedParamValue { 172 return fmt.Errorf("Chaincode version is not provided for %s", cmd.Name()) 173 } 174 } 175 176 if escc != common.UndefinedParamValue { 177 logger.Infof("Using escc %s", escc) 178 } else { 179 logger.Info("Using default escc") 180 escc = "escc" 181 } 182 183 if vscc != common.UndefinedParamValue { 184 logger.Infof("Using vscc %s", vscc) 185 } else { 186 logger.Info("Using default vscc") 187 vscc = "vscc" 188 } 189 190 if policy != common.UndefinedParamValue { 191 p, err := cauthdsl.FromString(policy) 192 if err != nil { 193 return fmt.Errorf("Invalid policy %s", policy) 194 } 195 policyMarhsalled = putils.MarshalOrPanic(p) 196 } 197 198 // Check that non-empty chaincode parameters contain only Args as a key. 199 // Type checking is done later when the JSON is actually unmarshaled 200 // into a pb.ChaincodeInput. To better understand what's going 201 // on here with JSON parsing see http://blog.golang.org/json-and-go - 202 // Generic JSON with interface{} 203 if chaincodeCtorJSON != "{}" { 204 var f interface{} 205 err := json.Unmarshal([]byte(chaincodeCtorJSON), &f) 206 if err != nil { 207 return fmt.Errorf("Chaincode argument error: %s", err) 208 } 209 m := f.(map[string]interface{}) 210 sm := make(map[string]interface{}) 211 for k := range m { 212 sm[strings.ToLower(k)] = m[k] 213 } 214 _, argsPresent := sm["args"] 215 _, funcPresent := sm["function"] 216 if !argsPresent || (len(m) == 2 && !funcPresent) || len(m) > 2 { 217 return errors.New("Non-empty JSON chaincode parameters must contain the following keys: 'Args' or 'Function' and 'Args'") 218 } 219 } else { 220 if cmd == nil || (cmd != chaincodeInstallCmd && cmd != chaincodePackageCmd) { 221 return errors.New("Empty JSON chaincode parameters must contain the following keys: 'Args' or 'Function' and 'Args'") 222 } 223 } 224 225 return nil 226 } 227 228 // ChaincodeCmdFactory holds the clients used by ChaincodeCmd 229 type ChaincodeCmdFactory struct { 230 EndorserClient pb.EndorserClient 231 Signer msp.SigningIdentity 232 BroadcastClient common.BroadcastClient 233 } 234 235 // InitCmdFactory init the ChaincodeCmdFactory with default clients 236 func InitCmdFactory(isEndorserRequired, isOrdererRequired bool) (*ChaincodeCmdFactory, error) { 237 var err error 238 var endorserClient pb.EndorserClient 239 if isEndorserRequired { 240 endorserClient, err = common.GetEndorserClientFnc() 241 if err != nil { 242 return nil, fmt.Errorf("Error getting endorser client %s: %s", chainFuncName, err) 243 } 244 } 245 246 signer, err := common.GetDefaultSignerFnc() 247 if err != nil { 248 return nil, fmt.Errorf("Error getting default signer: %s", err) 249 } 250 251 var broadcastClient common.BroadcastClient 252 if isOrdererRequired { 253 if len(orderingEndpoint) == 0 { 254 orderingEndpoints, err := common.GetOrdererEndpointOfChainFnc(chainID, signer, endorserClient) 255 if err != nil { 256 return nil, fmt.Errorf("Error getting (%s) orderer endpoint: %s", chainID, err) 257 } 258 if len(orderingEndpoints) == 0 { 259 return nil, fmt.Errorf("Error no orderer endpoint got for %s", chainID) 260 } 261 logger.Infof("Get chain(%s) orderer endpoint: %s", chainID, orderingEndpoints[0]) 262 orderingEndpoint = orderingEndpoints[0] 263 } 264 265 broadcastClient, err = common.GetBroadcastClientFnc(orderingEndpoint, tls, caFile) 266 267 if err != nil { 268 return nil, fmt.Errorf("Error getting broadcast client: %s", err) 269 } 270 } 271 return &ChaincodeCmdFactory{ 272 EndorserClient: endorserClient, 273 Signer: signer, 274 BroadcastClient: broadcastClient, 275 }, nil 276 } 277 278 // ChaincodeInvokeOrQuery invokes or queries the chaincode. If successful, the 279 // INVOKE form prints the ProposalResponse to STDOUT, and the QUERY form prints 280 // the query result on STDOUT. A command-line flag (-r, --raw) determines 281 // whether the query result is output as raw bytes, or as a printable string. 282 // The printable form is optionally (-x, --hex) a hexadecimal representation 283 // of the query response. If the query response is NIL, nothing is output. 284 // 285 // NOTE - Query will likely go away as all interactions with the endorser are 286 // Proposal and ProposalResponses 287 func ChaincodeInvokeOrQuery( 288 spec *pb.ChaincodeSpec, 289 cID string, 290 invoke bool, 291 signer msp.SigningIdentity, 292 endorserClient pb.EndorserClient, 293 bc common.BroadcastClient, 294 ) (*pb.ProposalResponse, error) { 295 // Build the ChaincodeInvocationSpec message 296 invocation := &pb.ChaincodeInvocationSpec{ChaincodeSpec: spec} 297 if customIDGenAlg != common.UndefinedParamValue { 298 invocation.IdGenerationAlg = customIDGenAlg 299 } 300 301 creator, err := signer.Serialize() 302 if err != nil { 303 return nil, fmt.Errorf("Error serializing identity for %s: %s", signer.GetIdentifier(), err) 304 } 305 306 funcName := "invoke" 307 if !invoke { 308 funcName = "query" 309 } 310 311 var prop *pb.Proposal 312 prop, _, err = putils.CreateProposalFromCIS(pcommon.HeaderType_ENDORSER_TRANSACTION, cID, invocation, creator) 313 if err != nil { 314 return nil, fmt.Errorf("Error creating proposal %s: %s", funcName, err) 315 } 316 317 var signedProp *pb.SignedProposal 318 signedProp, err = putils.GetSignedProposal(prop, signer) 319 if err != nil { 320 return nil, fmt.Errorf("Error creating signed proposal %s: %s", funcName, err) 321 } 322 323 var proposalResp *pb.ProposalResponse 324 proposalResp, err = endorserClient.ProcessProposal(context.Background(), signedProp) 325 if err != nil { 326 return nil, fmt.Errorf("Error endorsing %s: %s", funcName, err) 327 } 328 329 if invoke { 330 if proposalResp != nil { 331 if proposalResp.Response.Status >= shim.ERROR { 332 return proposalResp, nil 333 } 334 // assemble a signed transaction (it's an Envelope message) 335 env, err := putils.CreateSignedTx(prop, signer, proposalResp) 336 if err != nil { 337 return proposalResp, fmt.Errorf("Could not assemble transaction, err %s", err) 338 } 339 340 // send the envelope for ordering 341 if err = bc.Send(env); err != nil { 342 return proposalResp, fmt.Errorf("Error sending transaction %s: %s", funcName, err) 343 } 344 } 345 } 346 347 return proposalResp, nil 348 }