From 2d67d3873c50401dad45e309a65e02bc5dea68de Mon Sep 17 00:00:00 2001 From: Alessandro Sorniotti Date: Fri, 31 Aug 2018 21:34:55 +0200 Subject: [PATCH] [FAB-11830] Code hygiene for key-level validation tests -) avoid using sleeps -) use keyed fields -) log seed of randomness in case of assert violations Change-Id: I9fffa24159bfede8d8ce74cef680f271a6a9694b Signed-off-by: Alessandro Sorniotti Signed-off-by: Matthias Neugschwandtner --- .../statebased/validator_keylevel.go | 2 +- .../statebased/validator_keylevel_test.go | 60 +- .../common/validation/statebased/vpmanager.go | 4 +- .../validation/statebased/vpmanager_test.go | 582 +++++++++--------- .../validation/statebased/vpmanagerimpl.go | 12 +- .../builtin/1.3/validation_logic.go | 2 +- 6 files changed, 329 insertions(+), 333 deletions(-) diff --git a/core/common/validation/statebased/validator_keylevel.go b/core/common/validation/statebased/validator_keylevel.go index ec35e19668d..3308f47ac39 100644 --- a/core/common/validation/statebased/validator_keylevel.go +++ b/core/common/validation/statebased/validator_keylevel.go @@ -60,7 +60,7 @@ func (p *policyChecker) checkSBAndCCEP(cc, coll, key string, blockNum, txNum uin vp, err := p.vpmgr.GetValidationParameterForKey(cc, coll, key, blockNum, txNum) if err != nil { switch err := err.(type) { - case *ValidationParameterUpdatedErr: + case *ValidationParameterUpdatedError: return policyErr(err) default: return &commonerrors.VSCCExecutionFailureError{ diff --git a/core/common/validation/statebased/validator_keylevel_test.go b/core/common/validation/statebased/validator_keylevel_test.go index b3af29366d4..cb8383fb828 100644 --- a/core/common/validation/statebased/validator_keylevel_test.go +++ b/core/common/validation/statebased/validator_keylevel_test.go @@ -87,9 +87,9 @@ func TestKeylevelValidation(t *testing.T) { // We simulate policy check success and failure vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() - mr := &mockState{map[string][]byte{vpMetadataKey: []byte("EP")}, nil, map[string][]byte{vpMetadataKey: []byte("EP")}, nil, false} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}, GetPrivateDataMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} pe := &mockPolicyEvaluator{} validator := NewKeyLevelValidator(pe, pm) @@ -128,9 +128,9 @@ func TestKeylevelValidationPvtData(t *testing.T) { // We simulate policy check success and failure vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() - mr := &mockState{map[string][]byte{vpMetadataKey: []byte("EP")}, nil, map[string][]byte{vpMetadataKey: []byte("EP")}, nil, false} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}, GetPrivateDataMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} pe := &mockPolicyEvaluator{} validator := NewKeyLevelValidator(pe, pm) @@ -166,9 +166,9 @@ func TestKeylevelValidationMetaUpdate(t *testing.T) { // We simulate policy check success and failure vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() - mr := &mockState{map[string][]byte{vpMetadataKey: []byte("EP")}, nil, map[string][]byte{vpMetadataKey: []byte("EP")}, nil, false} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}, GetPrivateDataMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} pe := &mockPolicyEvaluator{} validator := NewKeyLevelValidator(pe, pm) @@ -204,9 +204,9 @@ func TestKeylevelValidationPvtMetaUpdate(t *testing.T) { // We simulate policy check success and failure vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() - mr := &mockState{map[string][]byte{vpMetadataKey: []byte("EP")}, nil, map[string][]byte{vpMetadataKey: []byte("EP")}, nil, false} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}, GetPrivateDataMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} pe := &mockPolicyEvaluator{} validator := NewKeyLevelValidator(pe, pm) @@ -242,9 +242,9 @@ func TestKeylevelValidationPolicyRetrievalFailure(t *testing.T) { // we simulate the case where we fail to retrieve // the validation parameters from the ledger. - mr := &mockState{nil, fmt.Errorf("metadata retrieval failure"), nil, nil, false} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataErr: fmt.Errorf("metadata retrieval failure")} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} validator := NewKeyLevelValidator(&mockPolicyEvaluator{}, pm) rwsb := rwsetBytes(t, "cc") @@ -269,9 +269,9 @@ func TestCCEPValidation(t *testing.T) { // touch any key with a state-based endorsement policy; // we expect to check the normal cc-endorsement policy. - mr := &mockState{map[string][]byte{}, nil, map[string][]byte{}, nil, false} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{}, GetPrivateDataMetadataRv: map[string][]byte{}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} pe := &mockPolicyEvaluator{} validator := NewKeyLevelValidator(pe, pm) @@ -309,9 +309,9 @@ func TestCCEPValidationReads(t *testing.T) { // touch any key with a state-based endorsement policy; // we expect to check the normal cc-endorsement policy. - mr := &mockState{map[string][]byte{}, nil, map[string][]byte{}, nil, false} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{}, GetPrivateDataMetadataRv: map[string][]byte{}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} pe := &mockPolicyEvaluator{} validator := NewKeyLevelValidator(pe, pm) @@ -349,9 +349,9 @@ func TestOnlySBEPChecked(t *testing.T) { // but the state-based one, and expect successful evaluation vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() - mr := &mockState{map[string][]byte{vpMetadataKey: []byte("SBEP")}, nil, map[string][]byte{}, nil, false} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("SBEP")}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} pe := &mockPolicyEvaluator{} validator := NewKeyLevelValidator(pe, pm) @@ -391,9 +391,9 @@ func TestCCEPValidationPvtReads(t *testing.T) { // touch any key with a state-based endorsement policy; // we expect to check the normal cc-endorsement policy. - mr := &mockState{map[string][]byte{}, nil, map[string][]byte{}, nil, false} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{}, GetPrivateDataMetadataRv: map[string][]byte{}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} pe := &mockPolicyEvaluator{} validator := NewKeyLevelValidator(pe, pm) @@ -431,9 +431,9 @@ func TestKeylevelValidationFailure(t *testing.T) { // for that very same key. vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() - mr := &mockState{map[string][]byte{vpMetadataKey: []byte("EP")}, nil, map[string][]byte{vpMetadataKey: []byte("EP")}, nil, false} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}, GetPrivateDataMetadataRv: map[string][]byte{vpMetadataKey: []byte("EP")}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} validator := NewKeyLevelValidator(&mockPolicyEvaluator{}, pm) rwsb := rwsetBytes(t, "cc") diff --git a/core/common/validation/statebased/vpmanager.go b/core/common/validation/statebased/vpmanager.go index b4f84207c78..5f8d2cd4441 100644 --- a/core/common/validation/statebased/vpmanager.go +++ b/core/common/validation/statebased/vpmanager.go @@ -13,12 +13,12 @@ import ( // ValidationParameterUpdatedErr is returned whenever // Validation Parameters for a key could not be // supplied because they are being updated -type ValidationParameterUpdatedErr struct { +type ValidationParameterUpdatedError struct { Key string Height uint64 } -func (f *ValidationParameterUpdatedErr) Error() string { +func (f *ValidationParameterUpdatedError) Error() string { return fmt.Sprintf("validation parameters for key %s have been changed in a transaction in block %d", f.Key, f.Height) } diff --git a/core/common/validation/statebased/vpmanager_test.go b/core/common/validation/statebased/vpmanager_test.go index 7cd63d0efc3..abc278fefa2 100644 --- a/core/common/validation/statebased/vpmanager_test.go +++ b/core/common/validation/statebased/vpmanager_test.go @@ -9,6 +9,7 @@ package statebased import ( "fmt" "math/rand" + "runtime" "strconv" "testing" "time" @@ -67,10 +68,10 @@ func TestSimple(t *testing.T) { vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() spe := cauthdsl.SignedByMspMember("foo") - mr := &mockState{map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, true} - ms := &mockStateFetcher{mr, nil} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, GetPrivateDataMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}} + ms := &mockStateFetcher{FetchStateRv: mr} pm := &KeyLevelValidationParameterManagerImpl{ - Support: ms, + StateFetcher: ms, } sp, err := pm.GetValidationParameterForKey("cc", "coll", "key", 0, 0) @@ -130,18 +131,24 @@ func pvtRwsetUpdatingMetadataFor(cc, coll, key string) []byte { }}) } -func runFunctions(funcArray []func(), t *testing.T) { - rand.Seed(time.Now().Unix()) - for _, i := range rand.Perm(len(funcArray)) { +func runFunctions(t *testing.T, seed int64, funcs ...func()) { + r := rand.New(rand.NewSource(seed)) + c := make(chan struct{}) + for _, i := range r.Perm(len(funcs)) { iLcl := i go func() { - assert.NotPanics(t, funcArray[iLcl]) + assert.NotPanics(t, funcs[iLcl], "assert failure occurred with seed %d", seed) + c <- struct{}{} }() } + for range funcs { + <-c + } } func TestDependencyNoConflict(t *testing.T) { t.Parallel() + seed := time.Now().Unix() // Scenario: validation parameter is retrieved successfully // for a ledger key for transaction (1,1) after waiting for @@ -152,40 +159,39 @@ func TestDependencyNoConflict(t *testing.T) { vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() spe := cauthdsl.SignedByMspMember("foo") - mr := &mockState{map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, true} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, GetPrivateDataMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} cc, coll, key := "cc", "", "key" rwsetbytes := rwsetUpdatingMetadataFor(cc, key) - resC := make(chan []byte) - errC := make(chan error) - runFunctions( - []func(){ - func() { - pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) - }, - func() { - pm.SetTxValidationResult(cc, 1, 0, errors.New("")) - }, - func() { - sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) - resC <- sp - errC <- err - }, - }, t) + resC := make(chan []byte, 1) + errC := make(chan error, 1) + runFunctions(t, seed, + func() { + pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) + }, + func() { + pm.SetTxValidationResult(cc, 1, 0, errors.New("")) + }, + func() { + sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) + resC <- sp + errC <- err + }) sp := <-resC err := <-errC - assert.NoError(t, err) - assert.Equal(t, utils.MarshalOrPanic(spe), sp) - assert.True(t, mr.DoneCalled) + assert.NoError(t, err, "assert failure occurred with seed %d", seed) + assert.Equal(t, utils.MarshalOrPanic(spe), sp, "assert failure occurred with seed %d", seed) + assert.True(t, mr.DoneCalled, "assert failure occurred with seed %d", seed) } func TestDependencyConflict(t *testing.T) { t.Parallel() + seed := time.Now().Unix() // Scenario: validation parameter is retrieved // for a ledger key for transaction (1,1) after waiting for @@ -197,41 +203,39 @@ func TestDependencyConflict(t *testing.T) { vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() spe := cauthdsl.SignedByMspMember("foo") - mr := &mockState{map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, true} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, GetPrivateDataMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} cc, coll, key := "cc", "", "key" rwsetbytes := rwsetUpdatingMetadataFor(cc, key) - resC := make(chan []byte) - errC := make(chan error) - runFunctions( - []func(){ - func() { - pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) - }, - func() { - pm.SetTxValidationResult(cc, 1, 0, nil) - }, - func() { - sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) - resC <- sp - errC <- err - }, - }, t) + resC := make(chan []byte, 1) + errC := make(chan error, 1) + runFunctions(t, seed, + func() { + pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) + }, + func() { + pm.SetTxValidationResult(cc, 1, 0, nil) + }, + func() { + sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) + resC <- sp + errC <- err + }) sp := <-resC err := <-errC - assert.Error(t, err) - assert.IsType(t, &ValidationParameterUpdatedErr{}, err) - assert.Nil(t, sp) - assert.True(t, mr.DoneCalled) + assert.Errorf(t, err, "assert failure occurred with seed %d", seed) + assert.IsType(t, &ValidationParameterUpdatedError{}, err, "assert failure occurred with seed %d", seed) + assert.Nil(t, sp, "assert failure occurred with seed %d", seed) } func TestMultipleDependencyNoConflict(t *testing.T) { t.Parallel() + seed := time.Now().Unix() // Scenario: validation parameter is retrieved successfully // for a ledger key for transaction (1,2) after waiting for @@ -242,46 +246,45 @@ func TestMultipleDependencyNoConflict(t *testing.T) { vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() spe := cauthdsl.SignedByMspMember("foo") - mr := &mockState{map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, true} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, GetPrivateDataMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} cc, coll, key := "cc", "", "key" rwsetbytes := rwsetUpdatingMetadataFor(cc, key) - resC := make(chan []byte) - errC := make(chan error) - runFunctions( - []func(){ - func() { - pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) - }, - func() { - pm.SetTxValidationResult(cc, 1, 0, errors.New("")) - }, - func() { - pm.ExtractValidationParameterDependency(1, 1, rwsetbytes) - }, - func() { - pm.SetTxValidationResult(cc, 1, 1, errors.New("")) - }, - func() { - sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 2) - resC <- sp - errC <- err - }, - }, t) + resC := make(chan []byte, 1) + errC := make(chan error, 1) + runFunctions(t, seed, + func() { + pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) + }, + func() { + pm.SetTxValidationResult(cc, 1, 0, errors.New("")) + }, + func() { + pm.ExtractValidationParameterDependency(1, 1, rwsetbytes) + }, + func() { + pm.SetTxValidationResult(cc, 1, 1, errors.New("")) + }, + func() { + sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 2) + resC <- sp + errC <- err + }) sp := <-resC err := <-errC - assert.NoError(t, err) - assert.Equal(t, utils.MarshalOrPanic(spe), sp) - assert.True(t, mr.DoneCalled) + assert.NoError(t, err, "assert failure occurred with seed %d", seed) + assert.Equal(t, utils.MarshalOrPanic(spe), sp, "assert failure occurred with seed %d", seed) + assert.True(t, mr.DoneCalled, "assert failure occurred with seed %d", seed) } func TestMultipleDependencyConflict(t *testing.T) { t.Parallel() + seed := time.Now().Unix() // Scenario: validation parameter is retrieved // for a ledger key for transaction (1,2) after waiting for @@ -293,123 +296,117 @@ func TestMultipleDependencyConflict(t *testing.T) { vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() spe := cauthdsl.SignedByMspMember("foo") - mr := &mockState{map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, true} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, GetPrivateDataMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} cc, coll, key := "cc", "", "key" rwsetbytes := rwsetUpdatingMetadataFor(cc, key) - resC := make(chan []byte) - errC := make(chan error) - runFunctions( - []func(){ - func() { - pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) - }, - func() { - pm.SetTxValidationResult(cc, 1, 0, errors.New("")) - }, - func() { - pm.ExtractValidationParameterDependency(1, 1, rwsetbytes) - }, - func() { - pm.SetTxValidationResult(cc, 1, 1, nil) - }, - func() { - sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 2) - resC <- sp - errC <- err - }, - }, t) + resC := make(chan []byte, 1) + errC := make(chan error, 1) + runFunctions(t, seed, + func() { + pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) + }, + func() { + pm.SetTxValidationResult(cc, 1, 0, errors.New("")) + }, + func() { + pm.ExtractValidationParameterDependency(1, 1, rwsetbytes) + }, + func() { + pm.SetTxValidationResult(cc, 1, 1, nil) + }, + func() { + sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 2) + resC <- sp + errC <- err + }) sp := <-resC err := <-errC - assert.Error(t, err) - assert.IsType(t, &ValidationParameterUpdatedErr{}, err) - assert.Nil(t, sp) - assert.True(t, mr.DoneCalled) + assert.Errorf(t, err, "assert failure occurred with seed %d", seed) + assert.IsType(t, &ValidationParameterUpdatedError{}, err, "assert failure occurred with seed %d", seed) + assert.Nil(t, sp, "assert failure occurred with seed %d", seed) } func TestPvtDependencyNoConflict(t *testing.T) { t.Parallel() + seed := time.Now().Unix() // Scenario: like TestDependencyNoConflict but for private data vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() spe := cauthdsl.SignedByMspMember("foo") - mr := &mockState{map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, true} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, GetPrivateDataMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} cc, coll, key := "cc", "coll", "key" rwsetBytes := pvtRwsetUpdatingMetadataFor(cc, coll, key) - resC := make(chan []byte) - errC := make(chan error) - runFunctions( - []func(){ - func() { - pm.ExtractValidationParameterDependency(1, 0, rwsetBytes) - }, - func() { - pm.SetTxValidationResult(cc, 1, 0, errors.New("")) - }, - func() { - sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) - resC <- sp - errC <- err - }, - }, t) + resC := make(chan []byte, 1) + errC := make(chan error, 1) + runFunctions(t, seed, + func() { + pm.ExtractValidationParameterDependency(1, 0, rwsetBytes) + }, + func() { + pm.SetTxValidationResult(cc, 1, 0, errors.New("")) + }, + func() { + sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) + resC <- sp + errC <- err + }) sp := <-resC err := <-errC - assert.NoError(t, err) - assert.Equal(t, utils.MarshalOrPanic(spe), sp) - assert.True(t, mr.DoneCalled) + assert.NoError(t, err, "assert failure occurred with seed %d", seed) + assert.Equal(t, utils.MarshalOrPanic(spe), sp, "assert failure occurred with seed %d", seed) + assert.True(t, mr.DoneCalled, "assert failure occurred with seed %d", seed) } func TestPvtDependencyConflict(t *testing.T) { t.Parallel() + seed := time.Now().Unix() // Scenario: like TestDependencyConflict but for private data vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() spe := cauthdsl.SignedByMspMember("foo") - mr := &mockState{map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, true} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, GetPrivateDataMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} cc, coll, key := "cc", "coll", "key" rwsetBytes := pvtRwsetUpdatingMetadataFor(cc, coll, key) - resC := make(chan []byte) - errC := make(chan error) - runFunctions( - []func(){ - func() { - pm.ExtractValidationParameterDependency(1, 0, rwsetBytes) - }, - func() { - pm.SetTxValidationResult(cc, 1, 0, nil) - }, - func() { - sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) - resC <- sp - errC <- err - }, - }, t) + resC := make(chan []byte, 1) + errC := make(chan error, 1) + runFunctions(t, seed, + func() { + pm.ExtractValidationParameterDependency(1, 0, rwsetBytes) + }, + func() { + pm.SetTxValidationResult(cc, 1, 0, nil) + }, + func() { + sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) + resC <- sp + errC <- err + }) sp := <-resC err := <-errC - assert.Error(t, err) - assert.IsType(t, &ValidationParameterUpdatedErr{}, err) - assert.True(t, len(err.Error()) > 0) - assert.Nil(t, sp) - assert.True(t, mr.DoneCalled) + assert.Errorf(t, err, "assert failure occurred with seed %d", seed) + assert.IsType(t, &ValidationParameterUpdatedError{}, err, "assert failure occurred with seed %d", seed) + assert.True(t, len(err.Error()) > 0, "assert failure occurred with seed %d", seed) + assert.Nil(t, sp, "assert failure occurred with seed %d", seed) } func TestBlockValidationTerminatesBeforeNewBlock(t *testing.T) { @@ -421,9 +418,9 @@ func TestBlockValidationTerminatesBeforeNewBlock(t *testing.T) { vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() spe := cauthdsl.SignedByMspMember("foo") - mr := &mockState{map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, true} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, GetPrivateDataMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} cc, coll, key := "cc", "coll", "key" @@ -434,11 +431,11 @@ func TestBlockValidationTerminatesBeforeNewBlock(t *testing.T) { pm.ExtractValidationParameterDependency(1, 0, rwsetBytes) } assert.Panics(t, panickingFunc) - assert.True(t, mr.DoneCalled) } func TestLedgerErrors(t *testing.T) { t.Parallel() + seed := time.Now().Unix() // Scenario: we check that if a ledger error occurs, // GetValidationParameterForKey returns an error @@ -447,46 +444,42 @@ func TestLedgerErrors(t *testing.T) { GetStateMetadataErr: fmt.Errorf("Ledger error"), GetPrivateDataMetadataErr: fmt.Errorf("Ledger error"), } - ms := &mockStateFetcher{mr, fmt.Errorf("Ledger error")} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + ms := &mockStateFetcher{FetchStateRv: mr, FetchStateErr: fmt.Errorf("Ledger error")} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} cc, coll, key := "cc", "", "key" rwsetbytes := rwsetUpdatingMetadataFor(cc, key) - errC := make(chan error) - runFunctions( - []func(){ - func() { - pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) - }, - func() { - pm.SetTxValidationResult(cc, 1, 0, errors.New("")) - }, - func() { - _, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) - errC <- err - }, - }, t) + errC := make(chan error, 1) + runFunctions(t, seed, + func() { + pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) + }, + func() { + pm.SetTxValidationResult(cc, 1, 0, errors.New("")) + }, + func() { + _, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) + errC <- err + }) err := <-errC - assert.Error(t, err) + assert.Errorf(t, err, "assert failure occurred with seed %d", seed) ms.FetchStateErr = nil - runFunctions( - []func(){ - func() { - pm.ExtractValidationParameterDependency(2, 0, rwsetbytes) - }, - func() { - pm.SetTxValidationResult(cc, 2, 0, errors.New("")) - }, - func() { - _, err := pm.GetValidationParameterForKey(cc, coll, key, 2, 1) - errC <- err - }, - }, t) + runFunctions(t, seed, + func() { + pm.ExtractValidationParameterDependency(2, 0, rwsetbytes) + }, + func() { + pm.SetTxValidationResult(cc, 2, 0, errors.New("")) + }, + func() { + _, err := pm.GetValidationParameterForKey(cc, coll, key, 2, 1) + errC <- err + }) err = <-errC assert.Error(t, err) @@ -495,27 +488,26 @@ func TestLedgerErrors(t *testing.T) { rwsetbytes = pvtRwsetUpdatingMetadataFor(cc, coll, key) - runFunctions( - []func(){ - func() { - pm.ExtractValidationParameterDependency(3, 0, rwsetbytes) - }, - func() { - pm.SetTxValidationResult(cc, 3, 0, errors.New("")) - }, - func() { - _, err = pm.GetValidationParameterForKey(cc, coll, key, 3, 1) - errC <- err - }, - }, t) + runFunctions(t, seed, + func() { + pm.ExtractValidationParameterDependency(3, 0, rwsetbytes) + }, + func() { + pm.SetTxValidationResult(cc, 3, 0, errors.New("")) + }, + func() { + _, err = pm.GetValidationParameterForKey(cc, coll, key, 3, 1) + errC <- err + }) err = <-errC - assert.Error(t, err) - assert.True(t, mr.DoneCalled) + assert.Errorf(t, err, "assert failure occurred with seed %d", seed) + assert.True(t, mr.DoneCalled, "assert failure occurred with seed %d", seed) } func TestBadRwsetIsNoDependency(t *testing.T) { t.Parallel() + seed := time.Now().Unix() // Scenario: a transaction has a bogus read-write set. // While the transaction will fail eventually, we check @@ -523,38 +515,37 @@ func TestBadRwsetIsNoDependency(t *testing.T) { vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() spe := cauthdsl.SignedByMspMember("foo") - mr := &mockState{map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, true} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, GetPrivateDataMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} cc, coll, key := "cc", "", "key" - resC := make(chan []byte) - errC := make(chan error) - runFunctions( - []func(){ - func() { - pm.ExtractValidationParameterDependency(1, 0, []byte("barf")) - }, - func() { - pm.SetTxValidationResult(cc, 1, 0, errors.New("")) - }, - func() { - sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) - resC <- sp - errC <- err - }, - }, t) + resC := make(chan []byte, 1) + errC := make(chan error, 1) + runFunctions(t, seed, + func() { + pm.ExtractValidationParameterDependency(1, 0, []byte("barf")) + }, + func() { + pm.SetTxValidationResult(cc, 1, 0, errors.New("")) + }, + func() { + sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) + resC <- sp + errC <- err + }) sp := <-resC err := <-errC - assert.NoError(t, err) - assert.Equal(t, utils.MarshalOrPanic(spe), sp) - assert.True(t, mr.DoneCalled) + assert.NoError(t, err, "assert failure occurred with seed %d", seed) + assert.Equal(t, utils.MarshalOrPanic(spe), sp, "assert failure occurred with seed %d", seed) + assert.True(t, mr.DoneCalled, "assert failure occurred with seed %d", seed) } func TestWritesIntoDifferentNamespaces(t *testing.T) { t.Parallel() + seed := time.Now().Unix() // Scenario: transaction (1,0) writes to namespace cc1. // Transaction (1,1) attempts to retrieve validation @@ -562,128 +553,133 @@ func TestWritesIntoDifferentNamespaces(t *testing.T) { vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() spe := cauthdsl.SignedByMspMember("foo") - mr := &mockState{map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, true} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, GetPrivateDataMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} cc, othercc, coll, key := "cc1", "cc", "", "key" rwsetbytes := rwsetUpdatingMetadataFor(cc, key) - resC := make(chan []byte) - errC := make(chan error) - runFunctions( - []func(){ - func() { - pm.SetTxValidationResult(cc, 1, 0, nil) - }, - func() { - pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) - sp, err := pm.GetValidationParameterForKey(othercc, coll, key, 1, 1) - resC <- sp - errC <- err - }, - }, t) + resC := make(chan []byte, 1) + errC := make(chan error, 1) + runFunctions(t, seed, + func() { + pm.SetTxValidationResult(cc, 1, 0, nil) + }, + func() { + pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) + sp, err := pm.GetValidationParameterForKey(othercc, coll, key, 1, 1) + resC <- sp + errC <- err + }) sp := <-resC err := <-errC - assert.NoError(t, err) - assert.Equal(t, utils.MarshalOrPanic(spe), sp) - assert.True(t, mr.DoneCalled) + assert.NoError(t, err, "assert failure occurred with seed %d", seed) + assert.Equal(t, utils.MarshalOrPanic(spe), sp, "assert failure occurred with seed %d", seed) + assert.True(t, mr.DoneCalled, "assert failure occurred with seed %d", seed) } func TestCombinedCalls(t *testing.T) { t.Parallel() + seed := time.Now().Unix() // Scenario: transaction (1,3) requests validation parameters // for different keys - one succeeds and one fails. vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() spe := cauthdsl.SignedByMspMember("foo") - mr := &mockState{map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, true} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, GetPrivateDataMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} cc := "cc" coll := "" key1 := "key1" key2 := "key2" - res1C := make(chan []byte) - err1C := make(chan error) - res2C := make(chan []byte) - err2C := make(chan error) - runFunctions( - []func(){ - func() { - pm.ExtractValidationParameterDependency(1, 0, rwsetUpdatingMetadataFor(cc, key1)) - }, - func() { - pm.SetTxValidationResult(cc, 1, 0, errors.New("")) - }, - func() { - pm.ExtractValidationParameterDependency(1, 1, rwsetUpdatingMetadataFor(cc, key2)) - }, - func() { - pm.SetTxValidationResult(cc, 1, 1, nil) - }, - func() { - sp, err := pm.GetValidationParameterForKey(cc, coll, key1, 1, 2) - res1C <- sp - err1C <- err - }, - func() { - sp, err := pm.GetValidationParameterForKey(cc, coll, key2, 1, 2) - res2C <- sp - err2C <- err - }, - }, t) + res1C := make(chan []byte, 1) + err1C := make(chan error, 1) + res2C := make(chan []byte, 1) + err2C := make(chan error, 1) + runFunctions(t, seed, + func() { + pm.ExtractValidationParameterDependency(1, 0, rwsetUpdatingMetadataFor(cc, key1)) + }, + func() { + pm.SetTxValidationResult(cc, 1, 0, errors.New("")) + }, + func() { + pm.ExtractValidationParameterDependency(1, 1, rwsetUpdatingMetadataFor(cc, key2)) + }, + func() { + pm.SetTxValidationResult(cc, 1, 1, nil) + }, + func() { + sp, err := pm.GetValidationParameterForKey(cc, coll, key1, 1, 2) + res1C <- sp + err1C <- err + }, + func() { + sp, err := pm.GetValidationParameterForKey(cc, coll, key2, 1, 2) + res2C <- sp + err2C <- err + }) sp := <-res1C err := <-err1C - assert.NoError(t, err) - assert.Equal(t, utils.MarshalOrPanic(spe), sp) + assert.NoError(t, err, "assert failure occurred with seed %d", seed) + assert.Equal(t, utils.MarshalOrPanic(spe), sp, "assert failure occurred with seed %d", seed) sp = <-res2C err = <-err2C - assert.Error(t, err) - assert.IsType(t, &ValidationParameterUpdatedErr{}, err) - assert.Nil(t, sp) + assert.Errorf(t, err, "assert failure occurred with seed %d", seed) + assert.IsType(t, &ValidationParameterUpdatedError{}, err, "assert failure occurred with seed %d", seed) + assert.Nil(t, sp, "assert failure occurred with seed %d", seed) - assert.True(t, mr.DoneCalled) + assert.True(t, mr.DoneCalled, "assert failure occurred with seed %d", seed) } func TestForRaces(t *testing.T) { + seed := time.Now().Unix() + // scenario to stress test the parallel validation // this is an extended combined test // run with go test -race and GOMAXPROCS >> 1 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() spe := cauthdsl.SignedByMspMember("foo") - mr := &mockState{map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, nil, true} - ms := &mockStateFetcher{mr, nil} - pm := &KeyLevelValidationParameterManagerImpl{Support: ms} + mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}, GetPrivateDataMetadataRv: map[string][]byte{vpMetadataKey: utils.MarshalOrPanic(spe)}} + ms := &mockStateFetcher{FetchStateRv: mr} + pm := &KeyLevelValidationParameterManagerImpl{StateFetcher: ms} cc := "cc" coll := "" - nRoutines := 8000 // race detector can track 8192 goroutines max + nRoutines := 1000 funcArray := make([]func(), nRoutines) - for i := 0; i < 8000; i++ { + for i := 0; i < nRoutines; i++ { txnum := i funcArray[i] = func() { key := strconv.Itoa(txnum) pm.ExtractValidationParameterDependency(1, uint64(txnum), rwsetUpdatingMetadataFor(cc, key)) - time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) + + // we yield in an attempt to create a more varied scheduling pattern in the hope of unearthing races + runtime.Gosched() + pm.SetTxValidationResult(cc, 1, uint64(txnum), errors.New("")) - time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) + + // we yield in an attempt to create a more varied scheduling pattern in the hope of unearthing races + runtime.Gosched() + sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 2) assert.Equal(t, utils.MarshalOrPanic(spe), sp) assert.NoError(t, err) } } - runFunctions(funcArray, t) + runFunctions(t, seed, funcArray...) - assert.True(t, mr.DoneCalled) + assert.True(t, mr.DoneCalled, "assert failure occurred with seed %d", seed) } diff --git a/core/common/validation/statebased/vpmanagerimpl.go b/core/common/validation/statebased/vpmanagerimpl.go index 64372ea00b4..e94026f31fc 100644 --- a/core/common/validation/statebased/vpmanagerimpl.go +++ b/core/common/validation/statebased/vpmanagerimpl.go @@ -46,10 +46,10 @@ type txDependency struct { mutex sync.Mutex cond *sync.Cond validationResultMap map[string]error - depInserted chan (struct{}) + depInserted chan struct{} } -func newTxDependency(txNum uint64) *txDependency { +func newTxDependency() *txDependency { txd := &txDependency{ depInserted: make(chan struct{}), validationResultMap: make(map[string]error), @@ -167,7 +167,7 @@ func (c *validationContext) getOrCreateDependencyByTxnum(txnum uint64) *txDepend defer c.mutex.Unlock() dep, ok = c.depsByTxnumMap[txnum] if !ok { - dep = newTxDependency(txnum) + dep = newTxDependency() c.depsByTxnumMap[txnum] = dep } } @@ -192,7 +192,7 @@ func (c *validationContext) waitForValidationResults(kid *ledgerKeyID, blockNum for depTxnum, dep := range dl { if depTxnum < txnum { if valErr := dep.waitForAndRetrieveValidationResult(kid.cc); valErr == nil { - err := &ValidationParameterUpdatedErr{kid.key, blockNum} + err := &ValidationParameterUpdatedError{kid.key, blockNum} return err } } @@ -207,7 +207,7 @@ func (c *validationContext) waitForValidationResults(kid *ledgerKeyID, blockNum type KeyLevelValidationParameterManagerImpl struct { // mutex ensures that only one goroutine at a time will modify validationCtxMap mutex sync.RWMutex - Support validation.StateFetcher + StateFetcher validation.StateFetcher validationCtx validationContext } @@ -274,7 +274,7 @@ func (m *KeyLevelValidationParameterManagerImpl) GetValidationParameterForKey(cc // if we're here, it means that it is safe to retrieve validation // parameters for the requested key from the ledger - state, err := m.Support.FetchState() + state, err := m.StateFetcher.FetchState() if err != nil { err = errors.WithMessage(err, "could not retrieve ledger") logger.Errorf(err.Error()) diff --git a/core/handlers/validation/builtin/1.3/validation_logic.go b/core/handlers/validation/builtin/1.3/validation_logic.go index 4c38db608fe..29187d4872f 100644 --- a/core/handlers/validation/builtin/1.3/validation_logic.go +++ b/core/handlers/validation/builtin/1.3/validation_logic.go @@ -40,7 +40,7 @@ var validCollectionNameRegex = regexp.MustCompile(ccmetadata.AllowedCharsCollect // New creates a new instance of the default VSCC // Typically this will only be invoked once per peer func New(c Capabilities, s StateFetcher, d IdentityDeserializer, pe PolicyEvaluator) *Validator { - vpmgr := &KeyLevelValidationParameterManagerImpl{Support: s} + vpmgr := &KeyLevelValidationParameterManagerImpl{StateFetcher: s} sbv := NewKeyLevelValidator(pe, vpmgr) return &Validator{