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