github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/chaincode/exectransaction.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 "errors" 21 "fmt" 22 23 "github.com/golang/protobuf/proto" 24 "golang.org/x/net/context" 25 26 "github.com/hyperledger/fabric/core/chaincode/shim" 27 "github.com/hyperledger/fabric/core/common/ccprovider" 28 "github.com/hyperledger/fabric/events/producer" 29 pb "github.com/hyperledger/fabric/protos/peer" 30 ) 31 32 //Execute - execute proposal, return original response of chaincode 33 func Execute(ctxt context.Context, cccid *ccprovider.CCContext, spec interface{}) (*pb.Response, *pb.ChaincodeEvent, error) { 34 var err error 35 var cds *pb.ChaincodeDeploymentSpec 36 var ci *pb.ChaincodeInvocationSpec 37 38 //init will call the Init method of a on a chain 39 cctyp := pb.ChaincodeMessage_INIT 40 if cds, _ = spec.(*pb.ChaincodeDeploymentSpec); cds == nil { 41 if ci, _ = spec.(*pb.ChaincodeInvocationSpec); ci == nil { 42 panic("Execute should be called with deployment or invocation spec") 43 } 44 cctyp = pb.ChaincodeMessage_TRANSACTION 45 } 46 47 cID, cMsg, err := theChaincodeSupport.Launch(ctxt, cccid, spec) 48 if err != nil { 49 return nil, nil, fmt.Errorf("%s", err) 50 } 51 52 //this should work because it worked above... 53 chaincode := cID.Name 54 55 if err != nil { 56 return nil, nil, fmt.Errorf("Failed to stablish stream to container %s", chaincode) 57 } 58 59 if err != nil { 60 return nil, nil, fmt.Errorf("Failed to retrieve chaincode spec(%s)", err) 61 } 62 63 var ccMsg *pb.ChaincodeMessage 64 ccMsg, err = createCCMessage(cctyp, cccid.TxID, cMsg) 65 if err != nil { 66 return nil, nil, fmt.Errorf("Failed to transaction message(%s)", err) 67 } 68 69 resp, err := theChaincodeSupport.Execute(ctxt, cccid, ccMsg, theChaincodeSupport.executetimeout) 70 if err != nil { 71 // Rollback transaction 72 return nil, nil, fmt.Errorf("Failed to execute transaction (%s)", err) 73 } else if resp == nil { 74 // Rollback transaction 75 return nil, nil, fmt.Errorf("Failed to receive a response for (%s)", cccid.TxID) 76 } 77 78 if resp.ChaincodeEvent != nil { 79 resp.ChaincodeEvent.ChaincodeId = cccid.Name 80 resp.ChaincodeEvent.TxId = cccid.TxID 81 } 82 83 if resp.Type == pb.ChaincodeMessage_COMPLETED { 84 res := &pb.Response{} 85 unmarshalErr := proto.Unmarshal(resp.Payload, res) 86 if unmarshalErr != nil { 87 return nil, nil, fmt.Errorf("Failed to unmarshal response for (%s): %s", cccid.TxID, unmarshalErr) 88 } 89 90 // Success 91 return res, resp.ChaincodeEvent, nil 92 } else if resp.Type == pb.ChaincodeMessage_ERROR { 93 // Rollback transaction 94 return nil, resp.ChaincodeEvent, fmt.Errorf("Transaction returned with failure: %s", string(resp.Payload)) 95 } 96 97 //TODO - this should never happen ... a panic is more appropriate but will save that for future 98 return nil, nil, fmt.Errorf("receive a response for (%s) but in invalid state(%d)", cccid.TxID, resp.Type) 99 } 100 101 // ExecuteWithErrorFilter is similar to Execute, but filters error contained in chaincode response and returns Payload of response only. 102 // Mostly used by unit-test. 103 func ExecuteWithErrorFilter(ctxt context.Context, cccid *ccprovider.CCContext, spec interface{}) ([]byte, *pb.ChaincodeEvent, error) { 104 res, event, err := Execute(ctxt, cccid, spec) 105 if err != nil { 106 chaincodeLogger.Errorf("ExecuteWithErrorFilter %s error: %s", cccid.Name, err) 107 return nil, nil, err 108 } 109 110 if res == nil { 111 chaincodeLogger.Errorf("ExecuteWithErrorFilter %s get nil response without error", cccid.Name) 112 return nil, nil, err 113 } 114 115 if res.Status != shim.OK { 116 return nil, nil, fmt.Errorf("%s", res.Message) 117 } 118 119 return res.Payload, event, nil 120 } 121 122 // GetSecureContext returns the security context from the context object or error 123 // Security context is nil if security is off from core.yaml file 124 // func GetSecureContext(ctxt context.Context) (crypto.Peer, error) { 125 // var err error 126 // temp := ctxt.Value("security") 127 // if nil != temp { 128 // if secCxt, ok := temp.(crypto.Peer); ok { 129 // return secCxt, nil 130 // } 131 // err = errors.New("Failed to convert security context type") 132 // } 133 // return nil, err 134 // } 135 136 var errFailedToGetChainCodeSpecForTransaction = errors.New("Failed to get ChainCodeSpec from Transaction") 137 138 func sendTxRejectedEvent(tx *pb.Transaction, errorMsg string) { 139 producer.Send(producer.CreateRejectionEvent(tx, errorMsg)) 140 }