github.com/ewagmig/fabric@v2.1.1+incompatible/core/common/validation/statebased/validator_keylevel_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package statebased
     8  
     9  import (
    10  	"fmt"
    11  	"testing"
    12  
    13  	"github.com/hyperledger/fabric-protos-go/common"
    14  	pb "github.com/hyperledger/fabric-protos-go/peer"
    15  	"github.com/hyperledger/fabric/common/errors"
    16  	"github.com/hyperledger/fabric/core/ledger"
    17  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
    18  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version"
    19  	"github.com/hyperledger/fabric/protoutil"
    20  	"github.com/stretchr/testify/assert"
    21  )
    22  
    23  type mockPolicyEvaluator struct {
    24  	EvaluateRV          error
    25  	EvaluateResByPolicy map[string]error
    26  }
    27  
    28  func (m *mockPolicyEvaluator) Evaluate(policyBytes []byte, signatureSet []*protoutil.SignedData) error {
    29  	if res, ok := m.EvaluateResByPolicy[string(policyBytes)]; ok {
    30  		return res
    31  	}
    32  
    33  	return m.EvaluateRV
    34  }
    35  
    36  func buildBlockWithTxs(txs ...[]byte) *common.Block {
    37  	return &common.Block{
    38  		Header: &common.BlockHeader{
    39  			Number: 1,
    40  		},
    41  		Data: &common.BlockData{
    42  			Data: txs,
    43  		},
    44  	}
    45  }
    46  
    47  func buildTXWithRwset(rws []byte) []byte {
    48  	return protoutil.MarshalOrPanic(&common.Envelope{
    49  		Payload: protoutil.MarshalOrPanic(
    50  			&common.Payload{
    51  				Data: protoutil.MarshalOrPanic(
    52  					&pb.Transaction{
    53  						Actions: []*pb.TransactionAction{
    54  							{
    55  								Payload: protoutil.MarshalOrPanic(&pb.ChaincodeActionPayload{
    56  									Action: &pb.ChaincodeEndorsedAction{
    57  										ProposalResponsePayload: protoutil.MarshalOrPanic(
    58  											&pb.ProposalResponsePayload{
    59  												Extension: protoutil.MarshalOrPanic(&pb.ChaincodeAction{Results: rws}),
    60  											},
    61  										),
    62  									},
    63  								}),
    64  							},
    65  						},
    66  					},
    67  				),
    68  			},
    69  		),
    70  	})
    71  }
    72  
    73  func rwsetBytes(t *testing.T, cc string) []byte {
    74  	rwsb := rwsetutil.NewRWSetBuilder()
    75  	rwsb.AddToWriteSet(cc, "key", []byte("value"))
    76  	rws := rwsb.GetTxReadWriteSet()
    77  	rwsetbytes, err := rws.ToProtoBytes()
    78  	assert.NoError(t, err)
    79  
    80  	return rwsetbytes
    81  }
    82  
    83  func TestKeylevelValidation(t *testing.T) {
    84  	t.Parallel()
    85  
    86  	// Scenario: we validate a transaction that writes
    87  	// to a key that contains key-level validation params.
    88  	// We simulate policy check success and failure
    89  
    90  	vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String()
    91  	mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: []byte("EP")}}
    92  	ms := &mockStateFetcher{FetchStateRv: mr}
    93  	pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms}
    94  	pe := &mockPolicyEvaluator{}
    95  	validator := NewKeyLevelValidator(NewV13Evaluator(pe, pm), pm)
    96  
    97  	rwsb := rwsetBytes(t, "cc")
    98  	prp := []byte("barf")
    99  	block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")))
   100  
   101  	validator.PreValidate(1, block)
   102  
   103  	endorsements := []*pb.Endorsement{
   104  		{
   105  			Signature: []byte("signature"),
   106  			Endorser:  []byte("endorser"),
   107  		},
   108  	}
   109  
   110  	go func() {
   111  		validator.PostValidate("cc", 1, 0, fmt.Errorf(""))
   112  	}()
   113  
   114  	err := validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), endorsements)
   115  	assert.NoError(t, err)
   116  
   117  	pe.EvaluateRV = fmt.Errorf("policy evaluation error")
   118  
   119  	err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), endorsements)
   120  	assert.Error(t, err)
   121  	assert.IsType(t, &errors.VSCCEndorsementPolicyError{}, err)
   122  }
   123  
   124  func TestKeylevelValidationPvtData(t *testing.T) {
   125  	t.Parallel()
   126  
   127  	// Scenario: we validate a transaction that writes
   128  	// to a pvt key that contains key-level validation params.
   129  	// We simulate policy check success and failure
   130  
   131  	vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String()
   132  	mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: []byte("EP")}}
   133  	ms := &mockStateFetcher{FetchStateRv: mr}
   134  	pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms}
   135  	pe := &mockPolicyEvaluator{}
   136  	validator := NewKeyLevelValidator(NewV13Evaluator(pe, pm), pm)
   137  
   138  	rwsbu := rwsetutil.NewRWSetBuilder()
   139  	rwsbu.AddToPvtAndHashedWriteSet("cc", "coll", "key", []byte("value"))
   140  	rws := rwsbu.GetTxReadWriteSet()
   141  	rwsb, err := rws.ToProtoBytes()
   142  	assert.NoError(t, err)
   143  	prp := []byte("barf")
   144  	block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")))
   145  
   146  	validator.PreValidate(1, block)
   147  
   148  	go func() {
   149  		validator.PostValidate("cc", 1, 0, fmt.Errorf(""))
   150  	}()
   151  
   152  	err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   153  	assert.NoError(t, err)
   154  
   155  	pe.EvaluateRV = fmt.Errorf("policy evaluation error")
   156  
   157  	err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   158  	assert.Error(t, err)
   159  	assert.IsType(t, &errors.VSCCEndorsementPolicyError{}, err)
   160  }
   161  
   162  func TestKeylevelValidationMetaUpdate(t *testing.T) {
   163  	t.Parallel()
   164  
   165  	// Scenario: we validate a transaction that updates
   166  	// the key-level validation parameters for a key.
   167  	// We simulate policy check success and failure
   168  
   169  	vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String()
   170  	mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: []byte("EP")}}
   171  	ms := &mockStateFetcher{FetchStateRv: mr}
   172  	pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms}
   173  	pe := &mockPolicyEvaluator{}
   174  	validator := NewKeyLevelValidator(NewV13Evaluator(pe, pm), pm)
   175  
   176  	rwsbu := rwsetutil.NewRWSetBuilder()
   177  	rwsbu.AddToMetadataWriteSet("cc", "key", map[string][]byte{})
   178  	rws := rwsbu.GetTxReadWriteSet()
   179  	rwsb, err := rws.ToProtoBytes()
   180  	assert.NoError(t, err)
   181  	prp := []byte("barf")
   182  	block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")))
   183  
   184  	validator.PreValidate(1, block)
   185  
   186  	go func() {
   187  		validator.PostValidate("cc", 1, 0, fmt.Errorf(""))
   188  	}()
   189  
   190  	err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   191  	assert.NoError(t, err)
   192  
   193  	pe.EvaluateRV = fmt.Errorf("policy evaluation error")
   194  
   195  	err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   196  	assert.Error(t, err)
   197  	assert.IsType(t, &errors.VSCCEndorsementPolicyError{}, err)
   198  }
   199  
   200  func TestKeylevelValidationPvtMetaUpdate(t *testing.T) {
   201  	t.Parallel()
   202  
   203  	// Scenario: we validate a transaction that updates
   204  	// the key-level validation parameters for a pvt key.
   205  	// We simulate policy check success and failure
   206  
   207  	vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String()
   208  	mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: []byte("EP")}}
   209  	ms := &mockStateFetcher{FetchStateRv: mr}
   210  	pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms}
   211  	pe := &mockPolicyEvaluator{}
   212  	validator := NewKeyLevelValidator(NewV13Evaluator(pe, pm), pm)
   213  
   214  	rwsbu := rwsetutil.NewRWSetBuilder()
   215  	rwsbu.AddToHashedMetadataWriteSet("cc", "coll", "key", map[string][]byte{})
   216  	rws := rwsbu.GetTxReadWriteSet()
   217  	rwsb, err := rws.ToProtoBytes()
   218  	assert.NoError(t, err)
   219  	prp := []byte("barf")
   220  	block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")))
   221  
   222  	validator.PreValidate(1, block)
   223  
   224  	go func() {
   225  		validator.PostValidate("cc", 1, 0, fmt.Errorf(""))
   226  	}()
   227  
   228  	err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   229  	assert.NoError(t, err)
   230  
   231  	pe.EvaluateRV = fmt.Errorf("policy evaluation error")
   232  
   233  	err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   234  	assert.Error(t, err)
   235  	assert.IsType(t, &errors.VSCCEndorsementPolicyError{}, err)
   236  }
   237  
   238  func TestKeylevelValidationPolicyRetrievalFailure(t *testing.T) {
   239  	t.Parallel()
   240  
   241  	// Scenario: we validate a transaction that updates
   242  	// the key-level validation parameters for a key.
   243  	// we simulate the case where we fail to retrieve
   244  	// the validation parameters from the ledger.
   245  
   246  	mr := &mockState{GetStateMetadataErr: fmt.Errorf("metadata retrieval failure")}
   247  	ms := &mockStateFetcher{FetchStateRv: mr}
   248  	pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms}
   249  	validator := NewKeyLevelValidator(NewV13Evaluator(&mockPolicyEvaluator{}, pm), pm)
   250  
   251  	rwsb := rwsetBytes(t, "cc")
   252  	prp := []byte("barf")
   253  	block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")))
   254  
   255  	validator.PreValidate(1, block)
   256  
   257  	go func() {
   258  		validator.PostValidate("cc", 1, 0, fmt.Errorf(""))
   259  	}()
   260  
   261  	err := validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   262  	assert.Error(t, err)
   263  	assert.IsType(t, &errors.VSCCExecutionFailureError{}, err)
   264  }
   265  
   266  func TestKeylevelValidationLedgerFailures(t *testing.T) {
   267  	// Scenario: we validate a transaction that updates
   268  	// the key-level validation parameters for a key.
   269  	// we simulate the case where we fail to retrieve
   270  	// the validation parameters from the ledger with
   271  	// both deterministic and non-deterministic errors
   272  
   273  	rwsb := rwsetBytes(t, "cc")
   274  	prp := []byte("barf")
   275  
   276  	t.Run("CollConfigNotDefinedError", func(t *testing.T) {
   277  		mr := &mockState{GetStateMetadataErr: &ledger.CollConfigNotDefinedError{Ns: "mycc"}}
   278  		ms := &mockStateFetcher{FetchStateRv: mr}
   279  		pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms}
   280  		validator := NewKeyLevelValidator(NewV13Evaluator(&mockPolicyEvaluator{}, pm), pm)
   281  
   282  		err := validator.Validate("cc", 1, 0, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   283  		assert.NoError(t, err)
   284  	})
   285  
   286  	t.Run("InvalidCollNameError", func(t *testing.T) {
   287  		mr := &mockState{GetStateMetadataErr: &ledger.InvalidCollNameError{Ns: "mycc", Coll: "mycoll"}}
   288  		ms := &mockStateFetcher{FetchStateRv: mr}
   289  		pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms}
   290  		validator := NewKeyLevelValidator(NewV13Evaluator(&mockPolicyEvaluator{}, pm), pm)
   291  
   292  		err := validator.Validate("cc", 1, 0, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   293  		assert.NoError(t, err)
   294  	})
   295  
   296  	t.Run("I/O error", func(t *testing.T) {
   297  		mr := &mockState{GetStateMetadataErr: fmt.Errorf("some I/O error")}
   298  		ms := &mockStateFetcher{FetchStateRv: mr}
   299  		pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms}
   300  		validator := NewKeyLevelValidator(NewV13Evaluator(&mockPolicyEvaluator{}, pm), pm)
   301  
   302  		err := validator.Validate("cc", 1, 0, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   303  		assert.Error(t, err)
   304  		assert.IsType(t, &errors.VSCCExecutionFailureError{}, err)
   305  	})
   306  }
   307  
   308  func TestCCEPValidation(t *testing.T) {
   309  	t.Parallel()
   310  
   311  	// Scenario: we validate a transaction that doesn't
   312  	// touch any key with a state-based endorsement policy;
   313  	// we expect to check the normal cc-endorsement policy.
   314  
   315  	mr := &mockState{GetStateMetadataRv: map[string][]byte{}, GetPrivateDataMetadataByHashRv: map[string][]byte{}}
   316  	ms := &mockStateFetcher{FetchStateRv: mr}
   317  	pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms}
   318  	pe := &mockPolicyEvaluator{}
   319  	validator := NewKeyLevelValidator(NewV13Evaluator(pe, pm), pm)
   320  
   321  	rwsbu := rwsetutil.NewRWSetBuilder()
   322  	rwsbu.AddToWriteSet("cc", "key", []byte("value"))
   323  	rwsbu.AddToWriteSet("cc", "key1", []byte("value"))
   324  	rwsbu.AddToReadSet("cc", "readkey", &version.Height{})
   325  	rwsbu.AddToHashedReadSet("cc", "coll", "readpvtkey", &version.Height{})
   326  	rws := rwsbu.GetTxReadWriteSet()
   327  	rwsb, err := rws.ToProtoBytes()
   328  	assert.NoError(t, err)
   329  	prp := []byte("barf")
   330  	block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")))
   331  
   332  	validator.PreValidate(1, block)
   333  
   334  	go func() {
   335  		validator.PostValidate("cc", 1, 0, fmt.Errorf(""))
   336  	}()
   337  
   338  	err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   339  	assert.NoError(t, err)
   340  
   341  	pe.EvaluateRV = fmt.Errorf("policy evaluation error")
   342  
   343  	err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   344  	assert.Error(t, err)
   345  	assert.IsType(t, &errors.VSCCEndorsementPolicyError{}, err)
   346  }
   347  
   348  func TestCCEPValidationReads(t *testing.T) {
   349  	t.Parallel()
   350  
   351  	// Scenario: we validate a transaction that doesn't
   352  	// touch any key with a state-based endorsement policy;
   353  	// we expect to check the normal cc-endorsement policy.
   354  
   355  	mr := &mockState{GetStateMetadataRv: map[string][]byte{}, GetPrivateDataMetadataByHashRv: map[string][]byte{}}
   356  	ms := &mockStateFetcher{FetchStateRv: mr}
   357  	pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms}
   358  	pe := &mockPolicyEvaluator{}
   359  	validator := NewKeyLevelValidator(NewV13Evaluator(pe, pm), pm)
   360  
   361  	rwsbu := rwsetutil.NewRWSetBuilder()
   362  	rwsbu.AddToReadSet("cc", "readkey", &version.Height{})
   363  	rws := rwsbu.GetTxReadWriteSet()
   364  	rwsb, err := rws.ToProtoBytes()
   365  	assert.NoError(t, err)
   366  	prp := []byte("barf")
   367  	block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")))
   368  
   369  	validator.PreValidate(1, block)
   370  
   371  	go func() {
   372  		validator.PostValidate("cc", 1, 0, fmt.Errorf(""))
   373  	}()
   374  
   375  	err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   376  	assert.NoError(t, err)
   377  
   378  	pe.EvaluateRV = fmt.Errorf("policy evaluation error")
   379  
   380  	err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   381  	assert.Error(t, err)
   382  	assert.IsType(t, &errors.VSCCEndorsementPolicyError{}, err)
   383  }
   384  
   385  func TestOnlySBEPChecked(t *testing.T) {
   386  	t.Parallel()
   387  
   388  	// Scenario: we ensure that as long as there is one key that
   389  	// requires state-based endorsement, we only check that policy
   390  	// and we do not check the cc-EP. We check that by setting up the
   391  	// policy evaluator mock into returning an error for all policies
   392  	// but the state-based one, and expect successful evaluation
   393  
   394  	vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String()
   395  	mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("SBEP")}}
   396  	ms := &mockStateFetcher{FetchStateRv: mr}
   397  	pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms}
   398  	pe := &mockPolicyEvaluator{}
   399  	validator := NewKeyLevelValidator(NewV13Evaluator(pe, pm), pm)
   400  
   401  	rwsb := rwsetBytes(t, "cc")
   402  	prp := []byte("barf")
   403  	block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")))
   404  
   405  	validator.PreValidate(1, block)
   406  
   407  	go func() {
   408  		validator.PostValidate("cc", 1, 0, fmt.Errorf(""))
   409  	}()
   410  
   411  	pe.EvaluateRV = fmt.Errorf("policy evaluation error")
   412  	pe.EvaluateResByPolicy = map[string]error{
   413  		"SBEP": nil,
   414  	}
   415  
   416  	err := validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   417  	assert.NoError(t, err)
   418  
   419  	// we also test with a read-write set that has a read as well as a write
   420  	rwsbu := rwsetutil.NewRWSetBuilder()
   421  	rwsbu.AddToWriteSet("cc", "key", []byte("value"))
   422  	rwsbu.AddToReadSet("cc", "key", nil)
   423  	rws := rwsbu.GetTxReadWriteSet()
   424  	rwsb, _ = rws.ToProtoBytes()
   425  
   426  	err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   427  	assert.NoError(t, err)
   428  }
   429  
   430  func TestCCEPValidationPvtReads(t *testing.T) {
   431  	t.Parallel()
   432  
   433  	// Scenario: we validate a transaction that doesn't
   434  	// touch any key with a state-based endorsement policy;
   435  	// we expect to check the normal cc-endorsement policy.
   436  
   437  	mr := &mockState{GetStateMetadataRv: map[string][]byte{}, GetPrivateDataMetadataByHashRv: map[string][]byte{}}
   438  	ms := &mockStateFetcher{FetchStateRv: mr}
   439  	pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms}
   440  	pe := &mockPolicyEvaluator{}
   441  	validator := NewKeyLevelValidator(NewV13Evaluator(pe, pm), pm)
   442  
   443  	rwsbu := rwsetutil.NewRWSetBuilder()
   444  	rwsbu.AddToHashedReadSet("cc", "coll", "readpvtkey", &version.Height{})
   445  	rws := rwsbu.GetTxReadWriteSet()
   446  	rwsb, err := rws.ToProtoBytes()
   447  	assert.NoError(t, err)
   448  	prp := []byte("barf")
   449  	block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")))
   450  
   451  	validator.PreValidate(1, block)
   452  
   453  	go func() {
   454  		validator.PostValidate("cc", 1, 0, fmt.Errorf(""))
   455  	}()
   456  
   457  	err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   458  	assert.NoError(t, err)
   459  
   460  	pe.EvaluateRV = fmt.Errorf("policy evaluation error")
   461  
   462  	err = validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   463  	assert.Error(t, err)
   464  	assert.IsType(t, &errors.VSCCEndorsementPolicyError{}, err)
   465  }
   466  
   467  func TestKeylevelValidationFailure(t *testing.T) {
   468  	t.Parallel()
   469  
   470  	// Scenario: we validate a transaction that writes
   471  	// to a key that contains key-level validation params.
   472  	// Validation fails because the block contains a previous
   473  	// transaction that updates the key-level validation params
   474  	// for that very same key.
   475  
   476  	vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String()
   477  	mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: []byte("EP")}}
   478  	ms := &mockStateFetcher{FetchStateRv: mr}
   479  	pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms}
   480  	validator := NewKeyLevelValidator(NewV13Evaluator(&mockPolicyEvaluator{}, pm), pm)
   481  
   482  	rwsb := rwsetBytes(t, "cc")
   483  	prp := []byte("barf")
   484  	block := buildBlockWithTxs(buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")), buildTXWithRwset(rwsetUpdatingMetadataFor("cc", "key")))
   485  
   486  	validator.PreValidate(1, block)
   487  
   488  	go func() {
   489  		validator.PostValidate("cc", 1, 0, nil)
   490  	}()
   491  
   492  	err := validator.Validate("cc", 1, 1, rwsb, prp, []byte("CCEP"), []*pb.Endorsement{})
   493  	assert.Error(t, err)
   494  	assert.IsType(t, &errors.VSCCEndorsementPolicyError{}, err)
   495  }