Skip to content

Commit a5e2d2b

Browse files
committed
FAB-1457 Change return value of chaincode
Replace return value of chaincode form ([]byte, error) to pb.Response. So that we can define different kinds of errors. More detail could be seen at https://jira.hyperledger.org/browse/FAB-1457. Now chaincode result will pass through shim/chaincode_spoort without converting. This commit define basic Status Code(200 for success and 500 for error). More code defination and handle logic will be added in following commit. Change chaincode examples interfaces and use basic code(200/500). Change-Id: I2ace7f4f654d343874274c26847f0dac91050d26 Signed-off-by: jiangyaoguo <[email protected]>
1 parent 230f3cc commit a5e2d2b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+976
-771
lines changed

core/chaincode/ccproviderimpl.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ func (c *ccProviderImpl) GetCCValidationInfoFromLCCC(ctxt context.Context, txid
8787
}
8888

8989
// ExecuteChaincode executes the chaincode specified in the context with the specified arguments
90-
func (c *ccProviderImpl) ExecuteChaincode(ctxt context.Context, cccid interface{}, args [][]byte) ([]byte, *peer.ChaincodeEvent, error) {
90+
func (c *ccProviderImpl) ExecuteChaincode(ctxt context.Context, cccid interface{}, args [][]byte) (*peer.Response, *peer.ChaincodeEvent, error) {
9191
return ExecuteChaincode(ctxt, cccid.(*ccProviderContextImpl).ctx, args)
9292
}
9393

core/chaincode/chaincode_support.go

+10
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"strings"
3333

3434
"github.com/hyperledger/fabric/common/flogging"
35+
"github.com/hyperledger/fabric/core/chaincode/shim"
3536
"github.com/hyperledger/fabric/core/container"
3637
"github.com/hyperledger/fabric/core/container/ccintf"
3738
"github.com/hyperledger/fabric/core/ledger"
@@ -340,6 +341,15 @@ func (chaincodeSupport *ChaincodeSupport) sendInitOrReady(context context.Contex
340341
if ccMsg.Type == pb.ChaincodeMessage_ERROR {
341342
err = fmt.Errorf("Error initializing container %s: %s", canName, string(ccMsg.Payload))
342343
}
344+
if ccMsg.Type == pb.ChaincodeMessage_COMPLETED {
345+
res := &pb.Response{}
346+
_ = proto.Unmarshal(ccMsg.Payload, res)
347+
if res.Status != shim.OK {
348+
err = fmt.Errorf("Error initializing container %s: %s", canName, string(res.Message))
349+
}
350+
// TODO
351+
// return res so that endorser can anylyze it.
352+
}
343353
case <-time.After(timeout):
344354
err = fmt.Errorf("Timeout expired while executing send init message")
345355
}

core/chaincode/chaincodeexec.go

+21-8
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
"github.com/golang/protobuf/proto"
2525
"github.com/hyperledger/fabric/common/util"
26+
"github.com/hyperledger/fabric/core/chaincode/shim"
2627
pb "github.com/hyperledger/fabric/protos/peer"
2728
)
2829

@@ -40,18 +41,28 @@ func createCIS(ccname string, args [][]byte) (*pb.ChaincodeInvocationSpec, error
4041
func GetCDSFromLCCC(ctxt context.Context, txid string, prop *pb.Proposal, chainID string, chaincodeID string) ([]byte, error) {
4142
version := util.GetSysCCVersion()
4243
cccid := NewCCContext(chainID, "lccc", version, txid, true, prop)
43-
payload, _, err := ExecuteChaincode(ctxt, cccid, [][]byte{[]byte("getdepspec"), []byte(chainID), []byte(chaincodeID)})
44-
return payload, err
44+
res, _, err := ExecuteChaincode(ctxt, cccid, [][]byte{[]byte("getdepspec"), []byte(chainID), []byte(chaincodeID)})
45+
if err != nil {
46+
return nil, fmt.Errorf("Execute getdepspec(%s, %s) of LCCC error: %s", chainID, chaincodeID, err)
47+
}
48+
if res.Status != shim.OK {
49+
return nil, fmt.Errorf("Get ChaincodeDeploymentSpec for %s/%s from LCCC error: %s", chaincodeID, chainID, res.Message)
50+
}
51+
52+
return res.Payload, nil
4553
}
4654

4755
// GetChaincodeDataFromLCCC gets chaincode data from LCCC given name
4856
func GetChaincodeDataFromLCCC(ctxt context.Context, txid string, prop *pb.Proposal, chainID string, chaincodeID string) (*ChaincodeData, error) {
4957
version := util.GetSysCCVersion()
5058
cccid := NewCCContext(chainID, "lccc", version, txid, true, prop)
51-
payload, _, err := ExecuteChaincode(ctxt, cccid, [][]byte{[]byte("getccdata"), []byte(chainID), []byte(chaincodeID)})
59+
res, _, err := ExecuteChaincode(ctxt, cccid, [][]byte{[]byte("getccdata"), []byte(chainID), []byte(chaincodeID)})
5260
if err == nil {
61+
if res.Status != shim.OK {
62+
return nil, fmt.Errorf("%s", res.Message)
63+
}
5364
cd := &ChaincodeData{}
54-
err = proto.Unmarshal(payload, cd)
65+
err = proto.Unmarshal(res.Payload, cd)
5566
if err != nil {
5667
return nil, err
5768
}
@@ -62,16 +73,18 @@ func GetChaincodeDataFromLCCC(ctxt context.Context, txid string, prop *pb.Propos
6273
}
6374

6475
// ExecuteChaincode executes a given chaincode given chaincode name and arguments
65-
func ExecuteChaincode(ctxt context.Context, cccid *CCContext, args [][]byte) ([]byte, *pb.ChaincodeEvent, error) {
76+
func ExecuteChaincode(ctxt context.Context, cccid *CCContext, args [][]byte) (*pb.Response, *pb.ChaincodeEvent, error) {
6677
var spec *pb.ChaincodeInvocationSpec
6778
var err error
68-
var b []byte
79+
var res *pb.Response
6980
var ccevent *pb.ChaincodeEvent
7081

7182
spec, err = createCIS(cccid.Name, args)
72-
b, ccevent, err = Execute(ctxt, cccid, spec)
83+
res, ccevent, err = Execute(ctxt, cccid, spec)
7384
if err != nil {
85+
chaincodeLogger.Errorf("Error executing chaincode: %s", err)
7486
return nil, nil, fmt.Errorf("Error executing chaincode: %s", err)
7587
}
76-
return b, ccevent, err
88+
89+
return res, ccevent, err
7790
}

core/chaincode/configer.go

+25-26
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ limitations under the License.
2222
package chaincode
2323

2424
import (
25-
"errors"
2625
"fmt"
2726

2827
"github.com/op/go-logging"
2928

3029
"github.com/hyperledger/fabric/core/chaincode/shim"
3130
"github.com/hyperledger/fabric/core/peer"
31+
pb "github.com/hyperledger/fabric/protos/peer"
3232
"github.com/hyperledger/fabric/protos/utils"
3333
)
3434

@@ -50,10 +50,9 @@ const (
5050
// Init is called once per chain when the chain is created.
5151
// This allows the chaincode to initialize any variables on the ledger prior
5252
// to any transaction execution on the chain.
53-
func (e *PeerConfiger) Init(stub shim.ChaincodeStubInterface) ([]byte, error) {
54-
cnflogger.Info("Init CSCC")
55-
56-
return nil, nil
53+
func (e *PeerConfiger) Init(stub shim.ChaincodeStubInterface) pb.Response {
54+
logger.Info("Init CSCC")
55+
return shim.Success(nil)
5756
}
5857

5958
// Invoke is called for the following:
@@ -66,11 +65,11 @@ func (e *PeerConfiger) Init(stub shim.ChaincodeStubInterface) ([]byte, error) {
6665
// # args[1] is a configuration Block if args[0] is JoinChain or
6766
// UpdateConfigBlock; otherwise it is the chain id
6867
// TODO: Improve the scc interface to avoid marshal/unmarshal args
69-
func (e *PeerConfiger) Invoke(stub shim.ChaincodeStubInterface) ([]byte, error) {
68+
func (e *PeerConfiger) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
7069
args := stub.GetArgs()
7170

7271
if len(args) < 2 {
73-
return nil, fmt.Errorf("Incorrect number of arguments, %d", len(args))
72+
return shim.Error(fmt.Sprintf("Incorrect number of arguments, %d", len(args)))
7473
}
7574
fname := string(args[0])
7675

@@ -86,72 +85,72 @@ func (e *PeerConfiger) Invoke(stub shim.ChaincodeStubInterface) ([]byte, error)
8685
return updateConfigBlock(args[1])
8786
}
8887

89-
return nil, fmt.Errorf("Requested function %s not found.", fname)
88+
return shim.Error(fmt.Sprintf("Requested function %s not found.", fname))
9089
}
9190

9291
// joinChain will join the specified chain in the configuration block.
9392
// Since it is the first block, it is the genesis block containing configuration
9493
// for this chain, so we want to update the Chain object with this info
95-
func joinChain(blockBytes []byte) ([]byte, error) {
94+
func joinChain(blockBytes []byte) pb.Response {
9695
if blockBytes == nil {
97-
return nil, fmt.Errorf("Genesis block must not be nil.")
96+
return shim.Error("Genesis block must not be nil.")
9897
}
9998

10099
block, err := utils.GetBlockFromBlockBytes(blockBytes)
101100
if err != nil {
102-
return nil, fmt.Errorf("Failed to reconstruct the genesis block, %s", err)
101+
return shim.Error(fmt.Sprintf("Failed to reconstruct the genesis block, %s", err))
103102
}
104103

105104
if err = peer.CreateChainFromBlock(block); err != nil {
106-
return nil, err
105+
return shim.Error(err.Error())
107106
}
108107

109108
chainID, err := utils.GetChainIDFromBlock(block)
110109
if err != nil {
111-
return nil, fmt.Errorf("Failed to get the chain ID from the configuration block, %s", err)
110+
return shim.Error(fmt.Sprintf("Failed to get the chain ID from the configuration block, %s", err))
112111
}
113112

114113
if err = peer.CreateDeliveryService(chainID); err != nil {
115-
return nil, err
114+
return shim.Error(err.Error())
116115
}
117116

118-
return []byte("200"), nil
117+
return shim.Success(nil)
119118
}
120119

121-
func updateConfigBlock(blockBytes []byte) ([]byte, error) {
120+
func updateConfigBlock(blockBytes []byte) pb.Response {
122121
if blockBytes == nil {
123-
return nil, errors.New("Configuration block must not be nil.")
122+
return shim.Error("Configuration block must not be nil.")
124123
}
125124
block, err := utils.GetBlockFromBlockBytes(blockBytes)
126125
if err != nil {
127-
return nil, fmt.Errorf("Failed to reconstruct the configuration block, %s", err)
126+
return shim.Error(fmt.Sprintf("Failed to reconstruct the configuration block, %s", err))
128127
}
129128
chainID, err := utils.GetChainIDFromBlock(block)
130129
if err != nil {
131-
return nil, fmt.Errorf("Failed to get the chain ID from the configuration block, %s", err)
130+
return shim.Error(fmt.Sprintf("Failed to get the chain ID from the configuration block, %s", err))
132131
}
133132

134133
if err := peer.SetCurrConfigBlock(block, chainID); err != nil {
135-
return nil, err
134+
return shim.Error(err.Error())
136135
}
137136

138-
return []byte("200"), nil
137+
return shim.Success(nil)
139138
}
140139

141140
// Return the current configuration block for the specified chainID. If the
142141
// peer doesn't belong to the chain, return error
143-
func getConfigBlock(chainID []byte) ([]byte, error) {
142+
func getConfigBlock(chainID []byte) pb.Response {
144143
if chainID == nil {
145-
return nil, errors.New("ChainID must not be nil.")
144+
return shim.Error("ChainID must not be nil.")
146145
}
147146
block := peer.GetCurrConfigBlock(string(chainID))
148147
if block == nil {
149-
return nil, fmt.Errorf("Unknown chain ID, %s", string(chainID))
148+
return shim.Error(fmt.Sprintf("Unknown chain ID, %s", string(chainID)))
150149
}
151150
blockBytes, err := utils.Marshal(block)
152151
if err != nil {
153-
return nil, err
152+
return shim.Error(err.Error())
154153
}
155154

156-
return blockBytes, nil
155+
return shim.Success(blockBytes)
157156
}

core/chaincode/configer_test.go

+11-13
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ func TestConfigerInit(t *testing.T) {
4141
e := new(PeerConfiger)
4242
stub := shim.NewMockStub("PeerConfiger", e)
4343

44-
if _, err := stub.MockInit("1", nil); err != nil {
45-
fmt.Println("Init failed", err)
44+
if res := stub.MockInit("1", nil); res.Status != shim.OK {
45+
fmt.Println("Init failed", string(res.Message))
4646
t.FailNow()
4747
}
4848
}
@@ -74,7 +74,7 @@ func TestConfigerInvokeJoinChainMissingParams(t *testing.T) {
7474
setupEndpoint(t)
7575
// Failed path: Not enough parameters
7676
args := [][]byte{[]byte("JoinChain")}
77-
if _, err := stub.MockInvoke("1", args); err == nil {
77+
if res := stub.MockInvoke("1", args); res.Status == shim.OK {
7878
t.Fatalf("cscc invoke JoinChain should have failed with invalid number of args: %v", args)
7979
}
8080
}
@@ -91,8 +91,7 @@ func TestConfigerInvokeJoinChainWrongParams(t *testing.T) {
9191

9292
// Failed path: wrong parameter type
9393
args := [][]byte{[]byte("JoinChain"), []byte("action")}
94-
if _, err := stub.MockInvoke("1", args); err == nil {
95-
fmt.Println("Invoke", args, "failed", err)
94+
if res := stub.MockInvoke("1", args); res.Status == shim.OK {
9695
t.Fatalf("cscc invoke JoinChain should have failed with null genesis block. args: %v", args)
9796
}
9897
}
@@ -124,7 +123,7 @@ func TestConfigerInvokeJoinChainCorrectParams(t *testing.T) {
124123
t.Fatalf("cscc invoke JoinChain failed because invalid block")
125124
}
126125
args := [][]byte{[]byte("JoinChain"), blockBytes}
127-
if _, err = stub.MockInvoke("1", args); err != nil {
126+
if res := stub.MockInvoke("1", args); res.Status != shim.OK {
128127
t.Fatalf("cscc invoke JoinChain failed with: %v", err)
129128
}
130129

@@ -135,7 +134,7 @@ func TestConfigerInvokeJoinChainCorrectParams(t *testing.T) {
135134
t.Fatalf("cscc invoke JoinChain failed with: %v", err)
136135
}
137136
args = [][]byte{[]byte("GetConfigBlock"), []byte(chainID)}
138-
if _, err = stub.MockInvoke("1", args); err != nil {
137+
if res := stub.MockInvoke("1", args); res.Status != shim.OK {
139138
t.Fatalf("cscc invoke GetConfigBlock failed with: %v", err)
140139
}
141140
}
@@ -149,14 +148,13 @@ func TestConfigerInvokeUpdateConfigBlock(t *testing.T) {
149148

150149
// Failed path: Not enough parameters
151150
args := [][]byte{[]byte("UpdateConfigBlock")}
152-
if _, err := stub.MockInvoke("1", args); err == nil {
151+
if res := stub.MockInvoke("1", args); res.Status == shim.OK {
153152
t.Fatalf("cscc invoke UpdateConfigBlock should have failed with invalid number of args: %v", args)
154153
}
155154

156155
// Failed path: wrong parameter type
157156
args = [][]byte{[]byte("UpdateConfigBlock"), []byte("action")}
158-
if _, err := stub.MockInvoke("1", args); err == nil {
159-
fmt.Println("Invoke", args, "failed", err)
157+
if res := stub.MockInvoke("1", args); res.Status == shim.OK {
160158
t.Fatalf("cscc invoke UpdateConfigBlock should have failed with null genesis block - args: %v", args)
161159
}
162160

@@ -166,8 +164,8 @@ func TestConfigerInvokeUpdateConfigBlock(t *testing.T) {
166164
t.Fatalf("cscc invoke UpdateConfigBlock failed because invalid block")
167165
}
168166
args = [][]byte{[]byte("UpdateConfigBlock"), blockBytes}
169-
if _, err := stub.MockInvoke("1", args); err != nil {
170-
t.Fatalf("cscc invoke UpdateConfigBlock failed with: %v", err)
167+
if res := stub.MockInvoke("1", args); res.Status != shim.OK {
168+
t.Fatalf("cscc invoke UpdateConfigBlock failed with: %v", res.Message)
171169
}
172170

173171
// Query the configuration block
@@ -177,7 +175,7 @@ func TestConfigerInvokeUpdateConfigBlock(t *testing.T) {
177175
t.Fatalf("cscc invoke UpdateConfigBlock failed with: %v", err)
178176
}
179177
args = [][]byte{[]byte("GetConfigBlock"), []byte(chainID)}
180-
if _, err := stub.MockInvoke("1", args); err != nil {
178+
if res := stub.MockInvoke("1", args); res.Status != shim.OK {
181179
t.Fatalf("cscc invoke GetConfigBlock failed with: %v", err)
182180
}
183181

core/chaincode/exectransaction.go

+33-5
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,16 @@ import (
2121
"fmt"
2222
"time"
2323

24+
"github.com/golang/protobuf/proto"
2425
"golang.org/x/net/context"
2526

27+
"github.com/hyperledger/fabric/core/chaincode/shim"
2628
"github.com/hyperledger/fabric/events/producer"
2729
pb "github.com/hyperledger/fabric/protos/peer"
2830
)
2931

30-
//Execute - execute proposal
31-
func Execute(ctxt context.Context, cccid *CCContext, spec interface{}) ([]byte, *pb.ChaincodeEvent, error) {
32+
//Execute - execute proposal, return original response of chaincode
33+
func Execute(ctxt context.Context, cccid *CCContext, spec interface{}) (*pb.Response, *pb.ChaincodeEvent, error) {
3234
var err error
3335
var cds *pb.ChaincodeDeploymentSpec
3436
var ci *pb.ChaincodeInvocationSpec
@@ -82,6 +84,11 @@ func Execute(ctxt context.Context, cccid *CCContext, spec interface{}) ([]byte,
8284
} else if resp == nil {
8385
// Rollback transaction
8486
return nil, nil, fmt.Errorf("Failed to receive a response for (%s)", cccid.TxID)
87+
}
88+
res := &pb.Response{}
89+
unmarshalErr := proto.Unmarshal(resp.Payload, res)
90+
if unmarshalErr != nil {
91+
return nil, nil, fmt.Errorf("Failed to unmarshal response for (%s): %s", cccid.TxID, unmarshalErr)
8592
} else {
8693
if resp.ChaincodeEvent != nil {
8794
resp.ChaincodeEvent.ChaincodeID = cccid.Name
@@ -90,16 +97,37 @@ func Execute(ctxt context.Context, cccid *CCContext, spec interface{}) ([]byte,
9097

9198
if resp.Type == pb.ChaincodeMessage_COMPLETED {
9299
// Success
93-
return resp.Payload, resp.ChaincodeEvent, nil
100+
return res, resp.ChaincodeEvent, nil
94101
} else if resp.Type == pb.ChaincodeMessage_ERROR {
95102
// Rollback transaction
96103
return nil, resp.ChaincodeEvent, fmt.Errorf("Transaction returned with failure: %s", string(resp.Payload))
97104
}
98-
return resp.Payload, nil, fmt.Errorf("receive a response for (%s) but in invalid state(%d)", cccid.TxID, resp.Type)
105+
return res, nil, fmt.Errorf("receive a response for (%s) but in invalid state(%d)", cccid.TxID, resp.Type)
99106
}
100107

101108
}
102-
return nil, nil, err
109+
return &pb.Response{Status: shim.OK, Payload: nil}, nil, err
110+
}
111+
112+
// ExecuteWithErrorFilter is similar to Execute, but filters error contained in chaincode response and returns Payload of response only.
113+
// Mostly used by unit-test.
114+
func ExecuteWithErrorFilter(ctxt context.Context, cccid *CCContext, spec interface{}) ([]byte, *pb.ChaincodeEvent, error) {
115+
res, event, err := Execute(ctxt, cccid, spec)
116+
if err != nil {
117+
chaincodeLogger.Errorf("ExecuteWithErrorFilter %s error: %s", cccid.Name, err)
118+
return nil, nil, err
119+
}
120+
121+
if res == nil {
122+
chaincodeLogger.Errorf("ExecuteWithErrorFilter %s get nil response without error", cccid.Name)
123+
return nil, nil, err
124+
}
125+
126+
if res.Status != shim.OK {
127+
return nil, nil, fmt.Errorf("%s", res.Message)
128+
}
129+
130+
return res.Payload, event, nil
103131
}
104132

105133
// GetSecureContext returns the security context from the context object or error

0 commit comments

Comments
 (0)