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