Skip to content

Commit

Permalink
[FAB-10843] Properly detect validation execution errors
Browse files Browse the repository at this point in the history
The validaton logic was not using a pointer type when comparing the
validation error returned from the plugin infrastructure, and thus
misclassified execution errors.

This change set:

1) Changes the Error() method in the API of the validation to have
   a pointer receiver, to prevent any implementer of Validate()
   to return by mistake a concrete type instead of a pointer type.
2) Adds an explicit cast in the plugin test to ensure that if a plugin
   Init() fails, an execution error is returned
3) Adds a test that simulates a failure in finding a plugin in the
   validation tests
4) Adds a test that simulates an execution error in a plugin, in the
   validation tests

Change-Id: Ic525e91fb7dc982d4deacffc0c1bf2a49331e90a
Signed-off-by: yacovm <yacovm@il.ibm.com>
  • Loading branch information
yacovm committed Jun 25, 2018
1 parent 2f8d10a commit 61a1290
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 3 deletions.
2 changes: 1 addition & 1 deletion core/committer/txvalidator/plugin_validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TestValidateWithPlugin(t *testing.T) {
factory.On("New").Return(plugin)
pm["vscc"] = factory
err = v.ValidateWithPlugin(ctx)
assert.Contains(t, err.Error(), "failed initializing plugin: foo")
assert.Contains(t, err.(*validation.ExecutionFailureError).Error(), "failed initializing plugin: foo")

// Scenario III: The plugin initialization succeeds but an execution error occurs.
// The plugin should pass the error as is.
Expand Down
61 changes: 61 additions & 0 deletions core/committer/txvalidator/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/hyperledger/fabric/core/committer/txvalidator/mocks"
"github.com/hyperledger/fabric/core/committer/txvalidator/testdata"
ccp "github.com/hyperledger/fabric/core/common/ccprovider"
"github.com/hyperledger/fabric/core/handlers/validation/api"
"github.com/hyperledger/fabric/core/ledger"
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
Expand Down Expand Up @@ -948,6 +949,66 @@ func TestValidationInvalidEndorsing(t *testing.T) {
assertInvalid(b, t, peer.TxValidationCode_ENDORSEMENT_POLICY_FAILURE)
}

func createMockLedger(t *testing.T, ccID string) *mockLedger {
l := new(mockLedger)
l.On("GetTransactionByID", mock.Anything).Return(&peer.ProcessedTransaction{}, ledger.NotFoundInIndexErr(""))
cd := &ccp.ChaincodeData{
Name: ccID,
Version: ccVersion,
Vscc: "vscc",
Policy: signedByAnyMember([]string{"SampleOrg"}),
}

cdbytes := utils.MarshalOrPanic(cd)
queryExecutor := new(mockQueryExecutor)
queryExecutor.On("GetState", "lscc", ccID).Return(cdbytes, nil)
l.On("NewQueryExecutor", mock.Anything).Return(queryExecutor, nil)
return l
}

func TestValidationPluginExecutionError(t *testing.T) {
plugin := &mocks.Plugin{}
plugin.On("Init", mock.Anything, mock.Anything, mock.Anything).Return(nil)

l, v := setupLedgerAndValidatorExplicit(t, &mockconfig.MockApplicationCapabilities{}, plugin)
defer ledgermgmt.CleanupTestEnv()
defer l.Close()

ccID := "mycc"
putCCInfo(l, ccID, signedByAnyMember([]string{"SampleOrg"}), t)

tx := getEnv(ccID, nil, createRWset(t, ccID), t)
b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}}

plugin.On("Validate", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&validation.ExecutionFailureError{
Reason: "I/O error",
})

err := v.Validate(b)
executionErr := err.(*commonerrors.VSCCExecutionFailureError)
assert.Contains(t, executionErr.Error(), "I/O error")
}

func TestValidationPluginNotFound(t *testing.T) {
ccID := "mycc"
tx := getEnv(ccID, nil, createRWset(t, ccID), t)
l := createMockLedger(t, ccID)
vcs := struct {
*mocktxvalidator.Support
*semaphore.Weighted
}{&mocktxvalidator.Support{LedgerVal: l, ACVal: &mockconfig.MockApplicationCapabilities{}}, semaphore.NewWeighted(10)}

b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}}

pm := &mocks.PluginMapper{}
pm.On("PluginFactoryByName", txvalidator.PluginName("vscc")).Return(nil)
mp := (&scc.MocksccProviderFactory{}).NewSystemChaincodeProvider()
validator := txvalidator.NewTxValidator(vcs, mp, pm)
err := validator.Validate(b)
executionErr := err.(*commonerrors.VSCCExecutionFailureError)
assert.Contains(t, executionErr.Error(), "plugin with name vscc wasn't found")
}

var signer msp.SigningIdentity

var signerSerialized []byte
Expand Down
2 changes: 1 addition & 1 deletion core/committer/txvalidator/vscc_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ func (v *VsccValidatorImpl) VSCCValidateTxForCC(ctx *Context) error {
return nil
}
// If the error is a pluggable validation execution error, cast it to the common errors ExecutionFailureError.
if e, isExecutionError := err.(validation.ExecutionFailureError); isExecutionError {
if e, isExecutionError := err.(*validation.ExecutionFailureError); isExecutionError {
return &commonerrors.VSCCExecutionFailureError{Err: e}
}
// Else, treat it as an endorsement error.
Expand Down
2 changes: 1 addition & 1 deletion core/handlers/validation/api/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ type ExecutionFailureError struct {

// Error conveys this is an error, and also contains
// the reason for the error
func (e ExecutionFailureError) Error() string {
func (e *ExecutionFailureError) Error() string {
return e.Reason
}

0 comments on commit 61a1290

Please sign in to comment.