From aad782e5da027b1e12aaf783e7d0cd150aee429a Mon Sep 17 00:00:00 2001 From: Matthew Sykes Date: Thu, 26 Apr 2018 14:43:14 -0400 Subject: [PATCH] [FAB-9735] Move execute variants into one file Change-Id: I15d11c3b000b58abd26be460281748e515b2515d Signed-off-by: Matthew Sykes --- core/chaincode/chaincode_support.go | 147 ++++++++++++++++++++++++++++ core/chaincode/chaincodeexec.go | 93 ------------------ core/chaincode/exectransaction.go | 109 --------------------- 3 files changed, 147 insertions(+), 202 deletions(-) delete mode 100644 core/chaincode/chaincodeexec.go delete mode 100644 core/chaincode/exectransaction.go diff --git a/core/chaincode/chaincode_support.go b/core/chaincode/chaincode_support.go index 46750f5d5e9..da3970448e0 100644 --- a/core/chaincode/chaincode_support.go +++ b/core/chaincode/chaincode_support.go @@ -11,7 +11,10 @@ import ( "time" "github.com/golang/protobuf/proto" + "github.com/hyperledger/fabric/common/resourcesconfig" + "github.com/hyperledger/fabric/common/util" "github.com/hyperledger/fabric/core/chaincode/accesscontrol" + "github.com/hyperledger/fabric/core/chaincode/shim" "github.com/hyperledger/fabric/core/common/ccprovider" "github.com/hyperledger/fabric/core/common/sysccprovider" "github.com/hyperledger/fabric/core/container" @@ -288,3 +291,147 @@ func (cs *ChaincodeSupport) Execute(ctxt context.Context, cccid *ccprovider.CCCo return ccresp, nil } + +//Execute - execute proposal, return original response of chaincode +func (cs *ChaincodeSupport) ExecuteSpec(ctxt context.Context, cccid *ccprovider.CCContext, spec ccprovider.ChaincodeSpecGetter) (*pb.Response, *pb.ChaincodeEvent, error) { + var err error + var cds *pb.ChaincodeDeploymentSpec + var ci *pb.ChaincodeInvocationSpec + + //init will call the Init method of a on a chain + cctyp := pb.ChaincodeMessage_INIT + if cds, _ = spec.(*pb.ChaincodeDeploymentSpec); cds == nil { + if ci, _ = spec.(*pb.ChaincodeInvocationSpec); ci == nil { + panic("Execute should be called with deployment or invocation spec") + } + cctyp = pb.ChaincodeMessage_TRANSACTION + } + + _, cMsg, err := cs.Launch(ctxt, cccid, spec) + if err != nil { + return nil, nil, err + } + + cMsg.Decorations = cccid.ProposalDecorations + + var ccMsg *pb.ChaincodeMessage + ccMsg, err = createCCMessage(cctyp, cccid.ChainID, cccid.TxID, cMsg) + if err != nil { + return nil, nil, errors.WithMessage(err, "failed to create chaincode message") + } + + resp, err := cs.Execute(ctxt, cccid, ccMsg, cs.executetimeout) + if err != nil { + // Rollback transaction + return nil, nil, errors.WithMessage(err, "failed to execute transaction") + } else if resp == nil { + // Rollback transaction + return nil, nil, errors.Errorf("failed to receive a response for txid (%s)", cccid.TxID) + } + + if resp.ChaincodeEvent != nil { + resp.ChaincodeEvent.ChaincodeId = cccid.Name + resp.ChaincodeEvent.TxId = cccid.TxID + } + + if resp.Type == pb.ChaincodeMessage_COMPLETED { + res := &pb.Response{} + unmarshalErr := proto.Unmarshal(resp.Payload, res) + if unmarshalErr != nil { + return nil, nil, errors.Wrap(unmarshalErr, fmt.Sprintf("failed to unmarshal response for txid (%s)", cccid.TxID)) + } + + // Success + return res, resp.ChaincodeEvent, nil + } else if resp.Type == pb.ChaincodeMessage_ERROR { + // Rollback transaction + return nil, resp.ChaincodeEvent, errors.Errorf("transaction returned with failure: %s", string(resp.Payload)) + } + + //TODO - this should never happen ... a panic is more appropriate but will save that for future + return nil, nil, errors.Errorf("receive a response for txid (%s) but in invalid state (%d)", cccid.TxID, resp.Type) +} + +// ExecuteWithErrorFilter is similar to Execute, but filters error contained in chaincode response and returns Payload of response only. +// Mostly used by unit-test. +func (cs *ChaincodeSupport) ExecuteWithErrorFilter(ctxt context.Context, cccid *ccprovider.CCContext, spec ccprovider.ChaincodeSpecGetter) ([]byte, *pb.ChaincodeEvent, error) { + res, event, err := cs.ExecuteSpec(ctxt, cccid, spec) + if err != nil { + chaincodeLogger.Errorf("ExecuteWithErrorFilter %s error: %+v", cccid.Name, err) + return nil, nil, err + } + + if res == nil { + chaincodeLogger.Errorf("ExecuteWithErrorFilter %s get nil response without error", cccid.Name) + return nil, nil, err + } + + if res.Status != shim.OK { + return nil, nil, errors.New(res.Message) + } + + return res.Payload, event, nil +} + +//create a chaincode invocation spec +func createCIS(ccname string, args [][]byte) (*pb.ChaincodeInvocationSpec, error) { + var err error + spec := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: &pb.ChaincodeID{Name: ccname}, Input: &pb.ChaincodeInput{Args: args}}} + if nil != err { + return nil, err + } + return spec, nil +} + +// GetCDS retrieves a chaincode deployment spec for the required chaincode +func (cs *ChaincodeSupport) GetCDS(ctxt context.Context, txid string, signedProp *pb.SignedProposal, prop *pb.Proposal, chainID string, chaincodeID string) ([]byte, error) { + version := util.GetSysCCVersion() + cccid := ccprovider.NewCCContext(chainID, "lscc", version, txid, true, signedProp, prop) + res, _, err := cs.ExecuteChaincode(ctxt, cccid, [][]byte{[]byte("getdepspec"), []byte(chainID), []byte(chaincodeID)}) + if err != nil { + return nil, errors.WithMessage(err, fmt.Sprintf("execute getdepspec(%s, %s) of LSCC error", chainID, chaincodeID)) + } + if res.Status != shim.OK { + return nil, errors.Errorf("get ChaincodeDeploymentSpec for %s/%s from LSCC error: %s", chaincodeID, chainID, res.Message) + } + + return res.Payload, nil +} + +// GetChaincodeDefinition returns resourcesconfig.ChaincodeDefinition for the chaincode with the supplied name +func (cs *ChaincodeSupport) GetChaincodeDefinition(ctxt context.Context, txid string, signedProp *pb.SignedProposal, prop *pb.Proposal, chainID string, chaincodeID string) (resourcesconfig.ChaincodeDefinition, error) { + version := util.GetSysCCVersion() + cccid := ccprovider.NewCCContext(chainID, "lscc", version, txid, true, signedProp, prop) + res, _, err := cs.ExecuteChaincode(ctxt, cccid, [][]byte{[]byte("getccdata"), []byte(chainID), []byte(chaincodeID)}) + if err == nil { + if res.Status != shim.OK { + return nil, errors.New(res.Message) + } + cd := &ccprovider.ChaincodeData{} + err = proto.Unmarshal(res.Payload, cd) + if err != nil { + return nil, err + } + return cd, nil + } + + return nil, err +} + +// ExecuteChaincode executes a given chaincode given chaincode name and arguments +func (cs *ChaincodeSupport) ExecuteChaincode(ctxt context.Context, cccid *ccprovider.CCContext, args [][]byte) (*pb.Response, *pb.ChaincodeEvent, error) { + var spec *pb.ChaincodeInvocationSpec + var err error + var res *pb.Response + var ccevent *pb.ChaincodeEvent + + spec, err = createCIS(cccid.Name, args) + res, ccevent, err = cs.ExecuteSpec(ctxt, cccid, spec) + if err != nil { + err = errors.WithMessage(err, "error executing chaincode") + chaincodeLogger.Errorf("%+v", err) + return nil, nil, err + } + + return res, ccevent, err +} diff --git a/core/chaincode/chaincodeexec.go b/core/chaincode/chaincodeexec.go deleted file mode 100644 index e1e16cdb785..00000000000 --- a/core/chaincode/chaincodeexec.go +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package chaincode - -import ( - "fmt" - - "github.com/golang/protobuf/proto" - "github.com/hyperledger/fabric/common/resourcesconfig" - "github.com/hyperledger/fabric/common/util" - "github.com/hyperledger/fabric/core/chaincode/shim" - "github.com/hyperledger/fabric/core/common/ccprovider" - pb "github.com/hyperledger/fabric/protos/peer" - "github.com/pkg/errors" - "golang.org/x/net/context" -) - -//create a chaincode invocation spec -func createCIS(ccname string, args [][]byte) (*pb.ChaincodeInvocationSpec, error) { - var err error - spec := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: &pb.ChaincodeID{Name: ccname}, Input: &pb.ChaincodeInput{Args: args}}} - if nil != err { - return nil, err - } - return spec, nil -} - -// GetCDS retrieves a chaincode deployment spec for the required chaincode -func (cs *ChaincodeSupport) GetCDS(ctxt context.Context, txid string, signedProp *pb.SignedProposal, prop *pb.Proposal, chainID string, chaincodeID string) ([]byte, error) { - version := util.GetSysCCVersion() - cccid := ccprovider.NewCCContext(chainID, "lscc", version, txid, true, signedProp, prop) - res, _, err := cs.ExecuteChaincode(ctxt, cccid, [][]byte{[]byte("getdepspec"), []byte(chainID), []byte(chaincodeID)}) - if err != nil { - return nil, errors.WithMessage(err, fmt.Sprintf("execute getdepspec(%s, %s) of LSCC error", chainID, chaincodeID)) - } - if res.Status != shim.OK { - return nil, errors.Errorf("get ChaincodeDeploymentSpec for %s/%s from LSCC error: %s", chaincodeID, chainID, res.Message) - } - - return res.Payload, nil -} - -// GetChaincodeDefinition returns resourcesconfig.ChaincodeDefinition for the chaincode with the supplied name -func (cs *ChaincodeSupport) GetChaincodeDefinition(ctxt context.Context, txid string, signedProp *pb.SignedProposal, prop *pb.Proposal, chainID string, chaincodeID string) (resourcesconfig.ChaincodeDefinition, error) { - version := util.GetSysCCVersion() - cccid := ccprovider.NewCCContext(chainID, "lscc", version, txid, true, signedProp, prop) - res, _, err := cs.ExecuteChaincode(ctxt, cccid, [][]byte{[]byte("getccdata"), []byte(chainID), []byte(chaincodeID)}) - if err == nil { - if res.Status != shim.OK { - return nil, errors.New(res.Message) - } - cd := &ccprovider.ChaincodeData{} - err = proto.Unmarshal(res.Payload, cd) - if err != nil { - return nil, err - } - return cd, nil - } - - return nil, err -} - -// ExecuteChaincode executes a given chaincode given chaincode name and arguments -func (cs *ChaincodeSupport) ExecuteChaincode(ctxt context.Context, cccid *ccprovider.CCContext, args [][]byte) (*pb.Response, *pb.ChaincodeEvent, error) { - var spec *pb.ChaincodeInvocationSpec - var err error - var res *pb.Response - var ccevent *pb.ChaincodeEvent - - spec, err = createCIS(cccid.Name, args) - res, ccevent, err = cs.ExecuteSpec(ctxt, cccid, spec) - if err != nil { - err = errors.WithMessage(err, "error executing chaincode") - chaincodeLogger.Errorf("%+v", err) - return nil, nil, err - } - - return res, ccevent, err -} diff --git a/core/chaincode/exectransaction.go b/core/chaincode/exectransaction.go deleted file mode 100644 index 6c64e572f29..00000000000 --- a/core/chaincode/exectransaction.go +++ /dev/null @@ -1,109 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package chaincode - -import ( - "fmt" - - "github.com/golang/protobuf/proto" - "github.com/hyperledger/fabric/core/chaincode/shim" - "github.com/hyperledger/fabric/core/common/ccprovider" - pb "github.com/hyperledger/fabric/protos/peer" - "github.com/pkg/errors" - "golang.org/x/net/context" -) - -//Execute - execute proposal, return original response of chaincode -func (cs *ChaincodeSupport) ExecuteSpec(ctxt context.Context, cccid *ccprovider.CCContext, spec ccprovider.ChaincodeSpecGetter) (*pb.Response, *pb.ChaincodeEvent, error) { - var err error - var cds *pb.ChaincodeDeploymentSpec - var ci *pb.ChaincodeInvocationSpec - - //init will call the Init method of a on a chain - cctyp := pb.ChaincodeMessage_INIT - if cds, _ = spec.(*pb.ChaincodeDeploymentSpec); cds == nil { - if ci, _ = spec.(*pb.ChaincodeInvocationSpec); ci == nil { - panic("Execute should be called with deployment or invocation spec") - } - cctyp = pb.ChaincodeMessage_TRANSACTION - } - - _, cMsg, err := cs.Launch(ctxt, cccid, spec) - if err != nil { - return nil, nil, err - } - - cMsg.Decorations = cccid.ProposalDecorations - - var ccMsg *pb.ChaincodeMessage - ccMsg, err = createCCMessage(cctyp, cccid.ChainID, cccid.TxID, cMsg) - if err != nil { - return nil, nil, errors.WithMessage(err, "failed to create chaincode message") - } - - resp, err := cs.Execute(ctxt, cccid, ccMsg, cs.executetimeout) - if err != nil { - // Rollback transaction - return nil, nil, errors.WithMessage(err, "failed to execute transaction") - } else if resp == nil { - // Rollback transaction - return nil, nil, errors.Errorf("failed to receive a response for txid (%s)", cccid.TxID) - } - - if resp.ChaincodeEvent != nil { - resp.ChaincodeEvent.ChaincodeId = cccid.Name - resp.ChaincodeEvent.TxId = cccid.TxID - } - - if resp.Type == pb.ChaincodeMessage_COMPLETED { - res := &pb.Response{} - unmarshalErr := proto.Unmarshal(resp.Payload, res) - if unmarshalErr != nil { - return nil, nil, errors.Wrap(unmarshalErr, fmt.Sprintf("failed to unmarshal response for txid (%s)", cccid.TxID)) - } - - // Success - return res, resp.ChaincodeEvent, nil - } else if resp.Type == pb.ChaincodeMessage_ERROR { - // Rollback transaction - return nil, resp.ChaincodeEvent, errors.Errorf("transaction returned with failure: %s", string(resp.Payload)) - } - - //TODO - this should never happen ... a panic is more appropriate but will save that for future - return nil, nil, errors.Errorf("receive a response for txid (%s) but in invalid state (%d)", cccid.TxID, resp.Type) -} - -// ExecuteWithErrorFilter is similar to Execute, but filters error contained in chaincode response and returns Payload of response only. -// Mostly used by unit-test. -func (cs *ChaincodeSupport) ExecuteWithErrorFilter(ctxt context.Context, cccid *ccprovider.CCContext, spec ccprovider.ChaincodeSpecGetter) ([]byte, *pb.ChaincodeEvent, error) { - res, event, err := cs.ExecuteSpec(ctxt, cccid, spec) - if err != nil { - chaincodeLogger.Errorf("ExecuteWithErrorFilter %s error: %+v", cccid.Name, err) - return nil, nil, err - } - - if res == nil { - chaincodeLogger.Errorf("ExecuteWithErrorFilter %s get nil response without error", cccid.Name) - return nil, nil, err - } - - if res.Status != shim.OK { - return nil, nil, errors.New(res.Message) - } - - return res.Payload, event, nil -}