Skip to content

Commit eb07744

Browse files
committed
[FAB-3618] Lower endorsement error threshold to 400
This CR lowers the threshold for endorsing/rejecting a proposal from 500 to 400. This keeps endorsement consistent with HTTP status codes, which define errors as having a status code >=400. Change-Id: Ib1e174905527858e232132d0ca1779d301e5e475 Signed-off-by: Will Lahti <[email protected]>
1 parent ed02047 commit eb07744

File tree

6 files changed

+58
-44
lines changed

6 files changed

+58
-44
lines changed

core/chaincode/shim/response.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@ import (
2020
)
2121

2222
const (
23-
// If status code less than 500, endorser will endorse it.
23+
// OK constant - status code less than 400, endorser will endorse it.
2424
// OK means init or invoke successfully.
2525
OK = 200
2626

27-
// Code that greater than or equal to 500 will be considered an error and rejected by endorser.
27+
// ERRORTHRESHOLD constant - status code greater than or equal to 400 will be considered an error and rejected by endorser.
28+
ERRORTHRESHOLD = 400
29+
30+
// ERROR constant - default error value
2831
ERROR = 500
2932
)
3033

core/endorser/endorser.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,10 @@ func (e *Endorser) callChaincode(ctxt context.Context, chainID string, version s
129129
return nil, nil, err
130130
}
131131

132-
//per doc anything < 500 can be sent as TX.
133-
//fabric errors will always be >= 500 (ie, unambiguous errors )
134-
//"lscc" will respond with status 200 or >=500 (ie, unambiguous OK or ERROR)
135-
if res.Status >= shim.ERROR {
132+
//per doc anything < 400 can be sent as TX.
133+
//fabric errors will always be >= 400 (ie, unambiguous errors )
134+
//"lscc" will respond with status 200 or 500 (ie, unambiguous OK or ERROR)
135+
if res.Status >= shim.ERRORTHRESHOLD {
136136
return res, nil, nil
137137
}
138138

@@ -370,7 +370,7 @@ func (e *Endorser) endorseProposal(ctx context.Context, chainID string, txid str
370370
return nil, err
371371
}
372372

373-
if res.Status >= shim.ERROR {
373+
if res.Status >= shim.ERRORTHRESHOLD {
374374
return &pb.ProposalResponse{Response: res}, nil
375375
}
376376

@@ -520,7 +520,7 @@ func (e *Endorser) ProcessProposal(ctx context.Context, signedProp *pb.SignedPro
520520
return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err
521521
}
522522
if pResp != nil {
523-
if res.Status >= shim.ERROR {
523+
if res.Status >= shim.ERRORTHRESHOLD {
524524
endorserLogger.Debugf("endorseProposal() resulted in chaincode error for txid: %s", txid)
525525
return pResp, &chaincodeError{res.Status, res.Message}
526526
}

core/scc/escc/endorser_onevalidsignature.go

+4-5
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ func (e *EndorserOneValidSignature) Init(stub shim.ChaincodeStubInterface) pb.Re
5757
// args[5] - binary blob of simulation results
5858
// args[6] - serialized events
5959
// args[7] - payloadVisibility
60-
6160
//
6261
// NOTE: this chaincode is meant to sign another chaincode's simulation
6362
// results. It should not manipulate state as any state change will be
@@ -101,7 +100,7 @@ func (e *EndorserOneValidSignature) Invoke(stub shim.ChaincodeStubInterface) pb.
101100
}
102101

103102
// handle executing chaincode result
104-
// Status code < 500 can be endorsed
103+
// Status code < shim.ERRORTHRESHOLD can be endorsed
105104
if args[4] == nil {
106105
return shim.Error("Response of chaincode executing is null")
107106
}
@@ -111,8 +110,8 @@ func (e *EndorserOneValidSignature) Invoke(stub shim.ChaincodeStubInterface) pb.
111110
return shim.Error(fmt.Sprintf("Failed to get Response of executing chaincode: %s", err.Error()))
112111
}
113112

114-
if response.Status >= shim.ERROR {
115-
return shim.Error(fmt.Sprintf("Status code less than 500 will be endorsed, get status code: %d", response.Status))
113+
if response.Status >= shim.ERRORTHRESHOLD {
114+
return shim.Error(fmt.Sprintf("Status code less than %d will be endorsed, received status code: %d", shim.ERRORTHRESHOLD, response.Status))
116115
}
117116

118117
// handle simulation results
@@ -164,7 +163,7 @@ func (e *EndorserOneValidSignature) Invoke(stub shim.ChaincodeStubInterface) pb.
164163
// marshall the proposal response so that we return its bytes
165164
prBytes, err := utils.GetBytesProposalResponse(presp)
166165
if err != nil {
167-
return shim.Error(fmt.Sprintf("Could not marshall ProposalResponse: err %s", err))
166+
return shim.Error(fmt.Sprintf("Could not marshal ProposalResponse: err %s", err))
168167
}
169168

170169
pResp, err := utils.GetProposalResponse(prBytes)

core/scc/escc/endorser_onevalidsignature_test.go

+14-6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"github.com/hyperledger/fabric/protos/common"
3232
pb "github.com/hyperledger/fabric/protos/peer"
3333
putils "github.com/hyperledger/fabric/protos/utils"
34+
"github.com/stretchr/testify/assert"
3435
)
3536

3637
func TestInit(t *testing.T) {
@@ -49,8 +50,10 @@ func TestInvoke(t *testing.T) {
4950
stub := shim.NewMockStub("endorseronevalidsignature", e)
5051
successResponse := &pb.Response{Status: 200, Payload: []byte("payload")}
5152
failResponse := &pb.Response{Status: 500, Message: "error"}
53+
ccFailResponse := &pb.Response{Status: 400, Message: "chaincode error"}
5254
successRes, _ := putils.GetBytesResponse(successResponse)
5355
failRes, _ := putils.GetBytesResponse(failResponse)
56+
ccFailRes, _ := putils.GetBytesResponse(ccFailResponse)
5457
ccid := &pb.ChaincodeID{Name: "foo", Version: "v1"}
5558
ccidBytes, err := proto.Marshal(ccid)
5659
if err != nil {
@@ -152,12 +155,17 @@ func TestInvoke(t *testing.T) {
152155
t.Fatalf("escc invoke should have failed with a null action struct. args: %v", args)
153156
}
154157

155-
// Failed path: status code >=500
158+
// Failed path: status code = 500
156159
args = [][]byte{[]byte("test"), []byte("test"), []byte("test"), ccidBytes, failRes, []byte("test")}
157-
if res := stub.MockInvoke("1", args); res.Status == shim.OK {
158-
fmt.Println("Invoke", args, "failed", string(res.Message))
159-
t.Fatalf("escc invoke should have failed with a null response. args: %v", args)
160-
}
160+
res := stub.MockInvoke("1", args)
161+
assert.NotEqual(t, res.Status, shim.OK, "Invoke should have failed with status code: %d", ccFailResponse.Status)
162+
assert.Contains(t, res.Message, fmt.Sprintf("Status code less than %d will be endorsed", shim.ERRORTHRESHOLD))
163+
164+
// Failed path: status code = 400
165+
args = [][]byte{[]byte("test"), []byte("test"), []byte("test"), ccidBytes, ccFailRes, []byte("test")}
166+
res = stub.MockInvoke("1", args)
167+
assert.NotEqual(t, res.Status, shim.OK, "Invoke should have failed with status code: %d", ccFailResponse.Status)
168+
assert.Contains(t, res.Message, fmt.Sprintf("Status code less than %d will be endorsed", shim.ERRORTHRESHOLD))
161169

162170
// Successful path - create a proposal
163171
cs := &pb.ChaincodeSpec{
@@ -199,7 +207,7 @@ func TestInvoke(t *testing.T) {
199207

200208
// success test 1: invocation with mandatory args only
201209
args = [][]byte{[]byte(""), proposal.Header, proposal.Payload, ccidBytes, successRes, simRes}
202-
res := stub.MockInvoke("1", args)
210+
res = stub.MockInvoke("1", args)
203211
if res.Status != shim.OK {
204212
t.Fail()
205213
t.Fatalf("escc invoke failed with: %s", res.Message)

peer/chaincode/invoke_test.go

+28-24
Original file line numberDiff line numberDiff line change
@@ -139,31 +139,35 @@ func TestInvokeCmdEndorsementError(t *testing.T) {
139139

140140
func TestInvokeCmdEndorsementFailure(t *testing.T) {
141141
InitMSP()
142-
ccRespStatus := int32(502)
143-
ccRespPayload := []byte("Invalid function name")
144-
mockCF, err := getMockChaincodeCmdFactoryEndorsementFailure(ccRespStatus, ccRespPayload)
145-
assert.NoError(t, err, "Error getting mock chaincode command factory")
146-
147-
cmd := invokeCmd(mockCF)
148-
AddFlags(cmd)
149-
args := []string{"-n", "example02", "-p", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02",
150-
"-c", "{\"Args\": [\"invokeinvalid\",\"a\",\"b\",\"10\"]}"}
151-
cmd.SetArgs(args)
152-
153-
// set logger to logger with a backend that writes to a byte buffer
154-
var buffer bytes.Buffer
155-
logger.SetBackend(logging.AddModuleLevel(logging.NewLogBackend(&buffer, "", 0)))
156-
// reset the logger after test
157-
defer func() {
158-
flogging.Reset()
159-
}()
160-
// make sure buffer is "clean" before running the invoke
161-
buffer.Reset()
142+
ccRespStatus := [2]int32{502, 400}
143+
ccRespPayload := [][]byte{[]byte("Invalid function name"), []byte("Incorrect parameters")}
144+
145+
for i := 0; i < 2; i++ {
146+
mockCF, err := getMockChaincodeCmdFactoryEndorsementFailure(ccRespStatus[i], ccRespPayload[i])
147+
assert.NoError(t, err, "Error getting mock chaincode command factory")
148+
149+
cmd := invokeCmd(mockCF)
150+
AddFlags(cmd)
151+
args := []string{"-n", "example02", "-p", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02",
152+
"-c", "{\"Args\": [\"invokeinvalid\",\"a\",\"b\",\"10\"]}"}
153+
cmd.SetArgs(args)
154+
155+
// set logger to logger with a backend that writes to a byte buffer
156+
var buffer bytes.Buffer
157+
logger.SetBackend(logging.AddModuleLevel(logging.NewLogBackend(&buffer, "", 0)))
158+
// reset the logger after test
159+
defer func() {
160+
flogging.Reset()
161+
}()
162+
// make sure buffer is "clean" before running the invoke
163+
buffer.Reset()
164+
165+
err = cmd.Execute()
166+
assert.NoError(t, err)
167+
assert.Regexp(t, "Endorsement failure during invoke", buffer.String())
168+
assert.Regexp(t, fmt.Sprintf("chaincode result: status:%d payload:\"%s\"", ccRespStatus[i], ccRespPayload[i]), buffer.String())
169+
}
162170

163-
err = cmd.Execute()
164-
assert.NoError(t, err)
165-
assert.Regexp(t, "Endorsement failure during invoke", buffer.String())
166-
assert.Regexp(t, fmt.Sprintf("chaincode result: status:%d payload:\"%s\"", ccRespStatus, ccRespPayload), buffer.String())
167171
}
168172

169173
// Returns mock chaincode command factory

protos/utils/txutils.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ func CreateProposalResponse(hdrbytes []byte, payl []byte, response *peer.Respons
252252

253253
// CreateProposalResponseFailure creates a proposal response for cases where
254254
// endorsement proposal fails either due to a endorsement failure or a chaincode
255-
// failure (chaincode response status >=500)
255+
// failure (chaincode response status >= shim.ERRORTHRESHOLD)
256256
func CreateProposalResponseFailure(hdrbytes []byte, payl []byte, response *peer.Response, results []byte, events []byte, ccid *peer.ChaincodeID, visibility []byte) (*peer.ProposalResponse, error) {
257257
hdr, err := GetHeader(hdrbytes)
258258
if err != nil {

0 commit comments

Comments
 (0)