github.com/defanghe/fabric@v2.1.1+incompatible/core/common/validation/statebased/vpmanager_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 "math/rand" 12 "runtime" 13 "strconv" 14 "sync" 15 "testing" 16 "time" 17 18 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 19 "github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset" 20 pb "github.com/hyperledger/fabric-protos-go/peer" 21 "github.com/hyperledger/fabric/common/policydsl" 22 validation "github.com/hyperledger/fabric/core/handlers/validation/api/state" 23 "github.com/hyperledger/fabric/protoutil" 24 "github.com/pkg/errors" 25 "github.com/stretchr/testify/assert" 26 ) 27 28 type mockState struct { 29 GetStateMetadataRv map[string][]byte 30 GetStateMetadataErr error 31 GetPrivateDataMetadataByHashRv map[string][]byte 32 GetPrivateDataMetadataByHashErr error 33 DoneCalled bool 34 } 35 36 func (ms *mockState) GetStateMultipleKeys(namespace string, keys []string) ([][]byte, error) { 37 return nil, nil 38 } 39 40 func (ms *mockState) GetStateRangeScanIterator(namespace string, startKey string, endKey string) (validation.ResultsIterator, error) { 41 return nil, nil 42 } 43 44 func (ms *mockState) GetStateMetadata(namespace, key string) (map[string][]byte, error) { 45 return ms.GetStateMetadataRv, ms.GetStateMetadataErr 46 } 47 48 func (ms *mockState) GetPrivateDataMetadataByHash(namespace, collection string, keyhash []byte) (map[string][]byte, error) { 49 return ms.GetPrivateDataMetadataByHashRv, ms.GetPrivateDataMetadataByHashErr 50 } 51 52 func (ms *mockState) Done() { 53 ms.DoneCalled = true 54 } 55 56 type mockStateFetcher struct { 57 mutex sync.Mutex 58 returnedStates []*mockState 59 FetchStateRv *mockState 60 FetchStateErr error 61 } 62 63 func (ms *mockStateFetcher) DoneCalled() bool { 64 for _, s := range ms.returnedStates { 65 if !s.DoneCalled { 66 return false 67 } 68 } 69 return true 70 } 71 72 type mockTranslator struct { 73 TranslateError error 74 } 75 76 func (n *mockTranslator) Translate(b []byte) ([]byte, error) { 77 return b, n.TranslateError 78 } 79 80 func (ms *mockStateFetcher) FetchState() (validation.State, error) { 81 var rv *mockState 82 if ms.FetchStateRv != nil { 83 rv = &mockState{ 84 GetPrivateDataMetadataByHashErr: ms.FetchStateRv.GetPrivateDataMetadataByHashErr, 85 GetStateMetadataErr: ms.FetchStateRv.GetStateMetadataErr, 86 GetPrivateDataMetadataByHashRv: ms.FetchStateRv.GetPrivateDataMetadataByHashRv, 87 GetStateMetadataRv: ms.FetchStateRv.GetStateMetadataRv, 88 } 89 ms.mutex.Lock() 90 if ms.returnedStates != nil { 91 ms.returnedStates = make([]*mockState, 0, 1) 92 } 93 ms.returnedStates = append(ms.returnedStates, rv) 94 ms.mutex.Unlock() 95 } 96 return rv, ms.FetchStateErr 97 } 98 99 func TestSimple(t *testing.T) { 100 t.Parallel() 101 102 // Scenario: validation parameter is retrieved with no dependency 103 104 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 105 spe := policydsl.SignedByMspMember("foo") 106 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}} 107 ms := &mockStateFetcher{FetchStateRv: mr} 108 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, 109 StateFetcher: ms, 110 } 111 112 sp, err := pm.GetValidationParameterForKey("cc", "coll", "key", 0, 0) 113 assert.NoError(t, err) 114 assert.Equal(t, protoutil.MarshalOrPanic(spe), sp) 115 assert.True(t, ms.DoneCalled()) 116 } 117 118 func rwsetUpdatingMetadataFor(cc, key string) []byte { 119 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 120 return protoutil.MarshalOrPanic( 121 &rwset.TxReadWriteSet{ 122 NsRwset: []*rwset.NsReadWriteSet{ 123 { 124 Namespace: cc, 125 Rwset: protoutil.MarshalOrPanic(&kvrwset.KVRWSet{ 126 MetadataWrites: []*kvrwset.KVMetadataWrite{ 127 { 128 Key: key, 129 Entries: []*kvrwset.KVMetadataEntry{ 130 { 131 Name: vpMetadataKey, 132 }, 133 }, 134 }, 135 }, 136 }), 137 }, 138 }}) 139 } 140 141 func pvtRwsetUpdatingMetadataFor(cc, coll, key string) []byte { 142 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 143 return protoutil.MarshalOrPanic( 144 &rwset.TxReadWriteSet{ 145 NsRwset: []*rwset.NsReadWriteSet{ 146 { 147 Namespace: cc, 148 CollectionHashedRwset: []*rwset.CollectionHashedReadWriteSet{ 149 { 150 CollectionName: coll, 151 HashedRwset: protoutil.MarshalOrPanic(&kvrwset.HashedRWSet{ 152 MetadataWrites: []*kvrwset.KVMetadataWriteHash{ 153 { 154 KeyHash: []byte(key), 155 Entries: []*kvrwset.KVMetadataEntry{ 156 { 157 Name: vpMetadataKey, 158 }, 159 }, 160 }, 161 }, 162 }), 163 }, 164 }, 165 }, 166 }}) 167 } 168 169 func runFunctions(t *testing.T, seed int64, funcs ...func()) { 170 r := rand.New(rand.NewSource(seed)) 171 c := make(chan struct{}) 172 for _, i := range r.Perm(len(funcs)) { 173 iLcl := i 174 go func() { 175 assert.NotPanics(t, funcs[iLcl], "assert failure occurred with seed %d", seed) 176 c <- struct{}{} 177 }() 178 } 179 for range funcs { 180 <-c 181 } 182 } 183 184 func TestTranslatorBadPolicy(t *testing.T) { 185 t.Parallel() 186 seed := time.Now().Unix() 187 188 // Scenario: we verify that translation from SignaturePolicyEnvelope to ApplicationPolicy fails appropriately 189 190 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 191 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("barf")}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: []byte("barf")}} 192 ms := &mockStateFetcher{FetchStateRv: mr} 193 mt := &mockTranslator{} 194 mt.TranslateError = errors.New("you shall not pass") 195 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: mt, StateFetcher: ms} 196 197 cc, coll, key := "cc", "", "key" 198 199 rwsetbytes := rwsetUpdatingMetadataFor(cc, key) 200 201 resC := make(chan []byte, 1) 202 errC := make(chan error, 1) 203 runFunctions(t, seed, 204 func() { 205 pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) 206 }, 207 func() { 208 pm.SetTxValidationResult(cc, 1, 0, errors.New("")) 209 }, 210 func() { 211 sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) 212 resC <- sp 213 errC <- err 214 }) 215 216 sp := <-resC 217 err := <-errC 218 assert.Errorf(t, err, "assert failure occurred with seed %d", seed) 219 assert.Contains(t, err.Error(), "could not translate policy for cc:key: you shall not pass", "assert failure occurred with seed %d", seed) 220 assert.True(t, ms.DoneCalled(), "assert failure occurred with seed %d", seed) 221 assert.Nil(t, sp, "assert failure occurred with seed %d", seed) 222 } 223 224 func TestTranslatorBadPolicyPvt(t *testing.T) { 225 t.Parallel() 226 seed := time.Now().Unix() 227 228 // Scenario: we verify that translation from SignaturePolicyEnvelope to ApplicationPolicy fails appropriately with private data 229 230 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 231 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: []byte("barf")}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: []byte("barf")}} 232 ms := &mockStateFetcher{FetchStateRv: mr} 233 mt := &mockTranslator{} 234 mt.TranslateError = errors.New("you shall not pass") 235 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: mt, StateFetcher: ms} 236 237 cc, coll, key := "cc", "coll", "key" 238 239 rwsetbytes := rwsetUpdatingMetadataFor(cc, key) 240 241 resC := make(chan []byte, 1) 242 errC := make(chan error, 1) 243 runFunctions(t, seed, 244 func() { 245 pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) 246 }, 247 func() { 248 pm.SetTxValidationResult(cc, 1, 0, errors.New("")) 249 }, 250 func() { 251 sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) 252 resC <- sp 253 errC <- err 254 }) 255 256 sp := <-resC 257 err := <-errC 258 assert.Errorf(t, err, "assert failure occurred with seed %d", seed) 259 assert.Contains(t, err.Error(), "could not translate policy for cc:coll:6b6579: you shall not pass", "assert failure occurred with seed %d", seed) 260 assert.True(t, ms.DoneCalled(), "assert failure occurred with seed %d", seed) 261 assert.Nil(t, sp, "assert failure occurred with seed %d", seed) 262 } 263 264 func TestDependencyNoConflict(t *testing.T) { 265 t.Parallel() 266 seed := time.Now().Unix() 267 268 // Scenario: validation parameter is retrieved successfully 269 // for a ledger key for transaction (1,1) after waiting for 270 // the dependency introduced by transaction (1,0). Retrieval 271 // was successful because transaction (1,0) was invalid and 272 // so we could safely retrieve the validation parameter from 273 // the ledger. 274 275 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 276 spe := policydsl.SignedByMspMember("foo") 277 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}} 278 ms := &mockStateFetcher{FetchStateRv: mr} 279 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 280 281 cc, coll, key := "cc", "", "key" 282 283 rwsetbytes := rwsetUpdatingMetadataFor(cc, key) 284 285 resC := make(chan []byte, 1) 286 errC := make(chan error, 1) 287 runFunctions(t, seed, 288 func() { 289 pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) 290 }, 291 func() { 292 pm.SetTxValidationResult(cc, 1, 0, errors.New("")) 293 }, 294 func() { 295 sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) 296 resC <- sp 297 errC <- err 298 }) 299 300 sp := <-resC 301 err := <-errC 302 assert.NoError(t, err, "assert failure occurred with seed %d", seed) 303 assert.Equal(t, protoutil.MarshalOrPanic(spe), sp, "assert failure occurred with seed %d", seed) 304 assert.True(t, ms.DoneCalled(), "assert failure occurred with seed %d", seed) 305 } 306 307 func TestDependencyConflict(t *testing.T) { 308 t.Parallel() 309 seed := time.Now().Unix() 310 311 // Scenario: validation parameter is retrieved 312 // for a ledger key for transaction (1,1) after waiting for 313 // the dependency introduced by transaction (1,0). Retrieval 314 // fails because transaction (1,0) was valid and so we cannot 315 // retrieve the validation parameter from the ledger, given 316 // that transaction (1,0) may or may not be valid according 317 // to the ledger component because of MVCC checks 318 319 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 320 spe := policydsl.SignedByMspMember("foo") 321 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}} 322 ms := &mockStateFetcher{FetchStateRv: mr} 323 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 324 325 cc, coll, key := "cc", "", "key" 326 327 rwsetbytes := rwsetUpdatingMetadataFor(cc, key) 328 329 resC := make(chan []byte, 1) 330 errC := make(chan error, 1) 331 runFunctions(t, seed, 332 func() { 333 pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) 334 }, 335 func() { 336 pm.SetTxValidationResult(cc, 1, 0, nil) 337 }, 338 func() { 339 sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) 340 resC <- sp 341 errC <- err 342 }) 343 344 sp := <-resC 345 err := <-errC 346 assert.Errorf(t, err, "assert failure occurred with seed %d", seed) 347 assert.IsType(t, &ValidationParameterUpdatedError{}, err, "assert failure occurred with seed %d", seed) 348 assert.Nil(t, sp, "assert failure occurred with seed %d", seed) 349 } 350 351 func TestMultipleDependencyNoConflict(t *testing.T) { 352 t.Parallel() 353 seed := time.Now().Unix() 354 355 // Scenario: validation parameter is retrieved successfully 356 // for a ledger key for transaction (1,2) after waiting for 357 // the dependency introduced by transaction (1,0) and (1,1). 358 // Retrieval was successful because both were invalid and 359 // so we could safely retrieve the validation parameter from 360 // the ledger. 361 362 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 363 spe := policydsl.SignedByMspMember("foo") 364 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}} 365 ms := &mockStateFetcher{FetchStateRv: mr} 366 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 367 368 cc, coll, key := "cc", "", "key" 369 370 rwsetbytes := rwsetUpdatingMetadataFor(cc, key) 371 372 resC := make(chan []byte, 1) 373 errC := make(chan error, 1) 374 runFunctions(t, seed, 375 func() { 376 pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) 377 }, 378 func() { 379 pm.SetTxValidationResult(cc, 1, 0, errors.New("")) 380 }, 381 func() { 382 pm.ExtractValidationParameterDependency(1, 1, rwsetbytes) 383 }, 384 func() { 385 pm.SetTxValidationResult(cc, 1, 1, errors.New("")) 386 }, 387 func() { 388 sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 2) 389 resC <- sp 390 errC <- err 391 }) 392 393 sp := <-resC 394 err := <-errC 395 assert.NoError(t, err, "assert failure occurred with seed %d", seed) 396 assert.Equal(t, protoutil.MarshalOrPanic(spe), sp, "assert failure occurred with seed %d", seed) 397 assert.True(t, ms.DoneCalled(), "assert failure occurred with seed %d", seed) 398 } 399 400 func TestMultipleDependencyConflict(t *testing.T) { 401 t.Parallel() 402 seed := time.Now().Unix() 403 404 // Scenario: validation parameter is retrieved 405 // for a ledger key for transaction (1,2) after waiting for 406 // the dependency introduced by transaction (1,0) and (1,1). 407 // Retrieval fails because transaction (1,1) is valid and so 408 // we cannot retrieve the validation parameter from the ledger, 409 // given that transaction (1,0) may or may not be valid according 410 // to the ledger component because of MVCC checks 411 412 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 413 spe := policydsl.SignedByMspMember("foo") 414 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}} 415 ms := &mockStateFetcher{FetchStateRv: mr} 416 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 417 418 cc, coll, key := "cc", "", "key" 419 420 rwsetbytes := rwsetUpdatingMetadataFor(cc, key) 421 422 resC := make(chan []byte, 1) 423 errC := make(chan error, 1) 424 runFunctions(t, seed, 425 func() { 426 pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) 427 }, 428 func() { 429 pm.SetTxValidationResult(cc, 1, 0, errors.New("")) 430 }, 431 func() { 432 pm.ExtractValidationParameterDependency(1, 1, rwsetbytes) 433 }, 434 func() { 435 pm.SetTxValidationResult(cc, 1, 1, nil) 436 }, 437 func() { 438 sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 2) 439 resC <- sp 440 errC <- err 441 }) 442 443 sp := <-resC 444 err := <-errC 445 assert.Errorf(t, err, "assert failure occurred with seed %d", seed) 446 assert.IsType(t, &ValidationParameterUpdatedError{}, err, "assert failure occurred with seed %d", seed) 447 assert.Nil(t, sp, "assert failure occurred with seed %d", seed) 448 } 449 450 func TestPvtDependencyNoConflict(t *testing.T) { 451 t.Parallel() 452 seed := time.Now().Unix() 453 454 // Scenario: like TestDependencyNoConflict but for private data 455 456 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 457 spe := policydsl.SignedByMspMember("foo") 458 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}} 459 ms := &mockStateFetcher{FetchStateRv: mr} 460 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 461 462 cc, coll, key := "cc", "coll", "key" 463 464 rwsetBytes := pvtRwsetUpdatingMetadataFor(cc, coll, key) 465 466 resC := make(chan []byte, 1) 467 errC := make(chan error, 1) 468 runFunctions(t, seed, 469 func() { 470 pm.ExtractValidationParameterDependency(1, 0, rwsetBytes) 471 }, 472 func() { 473 pm.SetTxValidationResult(cc, 1, 0, errors.New("")) 474 }, 475 func() { 476 sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) 477 resC <- sp 478 errC <- err 479 }) 480 481 sp := <-resC 482 err := <-errC 483 assert.NoError(t, err, "assert failure occurred with seed %d", seed) 484 assert.Equal(t, protoutil.MarshalOrPanic(spe), sp, "assert failure occurred with seed %d", seed) 485 assert.True(t, ms.DoneCalled(), "assert failure occurred with seed %d", seed) 486 } 487 488 func TestPvtDependencyConflict(t *testing.T) { 489 t.Parallel() 490 seed := time.Now().Unix() 491 492 // Scenario: like TestDependencyConflict but for private data 493 494 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 495 spe := policydsl.SignedByMspMember("foo") 496 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}} 497 ms := &mockStateFetcher{FetchStateRv: mr} 498 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 499 500 cc, coll, key := "cc", "coll", "key" 501 502 rwsetBytes := pvtRwsetUpdatingMetadataFor(cc, coll, key) 503 504 resC := make(chan []byte, 1) 505 errC := make(chan error, 1) 506 runFunctions(t, seed, 507 func() { 508 pm.ExtractValidationParameterDependency(1, 0, rwsetBytes) 509 }, 510 func() { 511 pm.SetTxValidationResult(cc, 1, 0, nil) 512 }, 513 func() { 514 sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) 515 resC <- sp 516 errC <- err 517 }) 518 519 sp := <-resC 520 err := <-errC 521 assert.Errorf(t, err, "assert failure occurred with seed %d", seed) 522 assert.IsType(t, &ValidationParameterUpdatedError{}, err, "assert failure occurred with seed %d", seed) 523 assert.True(t, len(err.Error()) > 0, "assert failure occurred with seed %d", seed) 524 assert.Nil(t, sp, "assert failure occurred with seed %d", seed) 525 } 526 527 func TestBlockValidationTerminatesBeforeNewBlock(t *testing.T) { 528 t.Parallel() 529 530 // Scenario: due to a programming error, validation for 531 // transaction (1,0) is scheduled after that for transaction 532 // (2,0). This cannot happen and so we panic 533 534 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 535 spe := policydsl.SignedByMspMember("foo") 536 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}} 537 ms := &mockStateFetcher{FetchStateRv: mr} 538 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 539 540 cc, coll, key := "cc", "coll", "key" 541 542 rwsetBytes := pvtRwsetUpdatingMetadataFor(cc, coll, key) 543 544 pm.ExtractValidationParameterDependency(2, 0, rwsetBytes) 545 panickingFunc := func() { 546 pm.ExtractValidationParameterDependency(1, 0, rwsetBytes) 547 } 548 assert.Panics(t, panickingFunc) 549 } 550 551 func TestLedgerErrors(t *testing.T) { 552 t.Parallel() 553 seed := time.Now().Unix() 554 555 // Scenario: we check that if a ledger error occurs, 556 // GetValidationParameterForKey returns an error 557 558 mr := &mockState{ 559 GetStateMetadataErr: fmt.Errorf("Ledger error"), 560 GetPrivateDataMetadataByHashErr: fmt.Errorf("Ledger error"), 561 } 562 ms := &mockStateFetcher{FetchStateRv: mr, FetchStateErr: fmt.Errorf("Ledger error")} 563 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 564 565 cc, coll, key := "cc", "", "key" 566 567 rwsetbytes := rwsetUpdatingMetadataFor(cc, key) 568 569 errC := make(chan error, 1) 570 runFunctions(t, seed, 571 func() { 572 pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) 573 }, 574 func() { 575 pm.SetTxValidationResult(cc, 1, 0, errors.New("")) 576 }, 577 func() { 578 _, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) 579 errC <- err 580 }) 581 582 err := <-errC 583 assert.Errorf(t, err, "assert failure occurred with seed %d", seed) 584 585 ms.FetchStateErr = nil 586 587 runFunctions(t, seed, 588 func() { 589 pm.ExtractValidationParameterDependency(2, 0, rwsetbytes) 590 }, 591 func() { 592 pm.SetTxValidationResult(cc, 2, 0, errors.New("")) 593 }, 594 func() { 595 _, err := pm.GetValidationParameterForKey(cc, coll, key, 2, 1) 596 errC <- err 597 }) 598 599 err = <-errC 600 assert.Error(t, err) 601 602 cc, coll, key = "cc", "coll", "key" 603 604 rwsetbytes = pvtRwsetUpdatingMetadataFor(cc, coll, key) 605 606 runFunctions(t, seed, 607 func() { 608 pm.ExtractValidationParameterDependency(3, 0, rwsetbytes) 609 }, 610 func() { 611 pm.SetTxValidationResult(cc, 3, 0, errors.New("")) 612 }, 613 func() { 614 _, err = pm.GetValidationParameterForKey(cc, coll, key, 3, 1) 615 errC <- err 616 }) 617 618 err = <-errC 619 assert.Errorf(t, err, "assert failure occurred with seed %d", seed) 620 assert.True(t, ms.DoneCalled(), "assert failure occurred with seed %d", seed) 621 } 622 623 func TestBadRwsetIsNoDependency(t *testing.T) { 624 t.Parallel() 625 seed := time.Now().Unix() 626 627 // Scenario: a transaction has a bogus read-write set. 628 // While the transaction will fail eventually, we check 629 // that our code doesn't break 630 631 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 632 spe := policydsl.SignedByMspMember("foo") 633 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}} 634 ms := &mockStateFetcher{FetchStateRv: mr} 635 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 636 637 cc, coll, key := "cc", "", "key" 638 639 resC := make(chan []byte, 1) 640 errC := make(chan error, 1) 641 runFunctions(t, seed, 642 func() { 643 pm.ExtractValidationParameterDependency(1, 0, []byte("barf")) 644 }, 645 func() { 646 pm.SetTxValidationResult(cc, 1, 0, errors.New("")) 647 }, 648 func() { 649 sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 1) 650 resC <- sp 651 errC <- err 652 }) 653 654 sp := <-resC 655 err := <-errC 656 assert.NoError(t, err, "assert failure occurred with seed %d", seed) 657 assert.Equal(t, protoutil.MarshalOrPanic(spe), sp, "assert failure occurred with seed %d", seed) 658 assert.True(t, ms.DoneCalled(), "assert failure occurred with seed %d", seed) 659 } 660 661 func TestWritesIntoDifferentNamespaces(t *testing.T) { 662 t.Parallel() 663 seed := time.Now().Unix() 664 665 // Scenario: transaction (1,0) writes to namespace cc1. 666 // Transaction (1,1) attempts to retrieve validation 667 // parameters for cc. This does not constitute a dependency 668 669 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 670 spe := policydsl.SignedByMspMember("foo") 671 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}} 672 ms := &mockStateFetcher{FetchStateRv: mr} 673 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 674 675 cc, othercc, coll, key := "cc1", "cc", "", "key" 676 677 rwsetbytes := rwsetUpdatingMetadataFor(cc, key) 678 679 resC := make(chan []byte, 1) 680 errC := make(chan error, 1) 681 runFunctions(t, seed, 682 func() { 683 pm.SetTxValidationResult(cc, 1, 0, nil) 684 }, 685 func() { 686 pm.ExtractValidationParameterDependency(1, 0, rwsetbytes) 687 sp, err := pm.GetValidationParameterForKey(othercc, coll, key, 1, 1) 688 resC <- sp 689 errC <- err 690 }) 691 692 sp := <-resC 693 err := <-errC 694 assert.NoError(t, err, "assert failure occurred with seed %d", seed) 695 assert.Equal(t, protoutil.MarshalOrPanic(spe), sp, "assert failure occurred with seed %d", seed) 696 assert.True(t, ms.DoneCalled(), "assert failure occurred with seed %d", seed) 697 } 698 699 func TestCombinedCalls(t *testing.T) { 700 t.Parallel() 701 seed := time.Now().Unix() 702 703 // Scenario: transaction (1,3) requests validation parameters 704 // for different keys - one succeeds and one fails. 705 706 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 707 spe := policydsl.SignedByMspMember("foo") 708 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}} 709 ms := &mockStateFetcher{FetchStateRv: mr} 710 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 711 712 cc := "cc" 713 coll := "" 714 key1 := "key1" 715 key2 := "key2" 716 717 res1C := make(chan []byte, 1) 718 err1C := make(chan error, 1) 719 res2C := make(chan []byte, 1) 720 err2C := make(chan error, 1) 721 runFunctions(t, seed, 722 func() { 723 pm.ExtractValidationParameterDependency(1, 0, rwsetUpdatingMetadataFor(cc, key1)) 724 }, 725 func() { 726 pm.SetTxValidationResult(cc, 1, 0, errors.New("")) 727 }, 728 func() { 729 pm.ExtractValidationParameterDependency(1, 1, rwsetUpdatingMetadataFor(cc, key2)) 730 }, 731 func() { 732 pm.SetTxValidationResult(cc, 1, 1, nil) 733 }, 734 func() { 735 sp, err := pm.GetValidationParameterForKey(cc, coll, key1, 1, 2) 736 res1C <- sp 737 err1C <- err 738 }, 739 func() { 740 sp, err := pm.GetValidationParameterForKey(cc, coll, key2, 1, 2) 741 res2C <- sp 742 err2C <- err 743 }) 744 745 sp := <-res1C 746 err := <-err1C 747 assert.NoError(t, err, "assert failure occurred with seed %d", seed) 748 assert.Equal(t, protoutil.MarshalOrPanic(spe), sp, "assert failure occurred with seed %d", seed) 749 750 sp = <-res2C 751 err = <-err2C 752 assert.Errorf(t, err, "assert failure occurred with seed %d", seed) 753 assert.IsType(t, &ValidationParameterUpdatedError{}, err, "assert failure occurred with seed %d", seed) 754 assert.Nil(t, sp, "assert failure occurred with seed %d", seed) 755 756 assert.True(t, ms.DoneCalled(), "assert failure occurred with seed %d", seed) 757 } 758 759 func TestForRaces(t *testing.T) { 760 seed := time.Now().Unix() 761 762 // scenario to stress test the parallel validation 763 // this is an extended combined test 764 // run with go test -race 765 766 vpMetadataKey := pb.MetaDataKeys_VALIDATION_PARAMETER.String() 767 spe := policydsl.SignedByMspMember("foo") 768 mr := &mockState{GetStateMetadataRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}, GetPrivateDataMetadataByHashRv: map[string][]byte{vpMetadataKey: protoutil.MarshalOrPanic(spe)}} 769 ms := &mockStateFetcher{FetchStateRv: mr} 770 pm := &KeyLevelValidationParameterManagerImpl{PolicyTranslator: &mockTranslator{}, StateFetcher: ms} 771 772 cc := "cc" 773 coll := "" 774 775 nRoutines := 1000 776 funcArray := make([]func(), nRoutines) 777 for i := 0; i < nRoutines; i++ { 778 txnum := i 779 funcArray[i] = func() { 780 key := strconv.Itoa(txnum) 781 pm.ExtractValidationParameterDependency(1, uint64(txnum), rwsetUpdatingMetadataFor(cc, key)) 782 783 // we yield in an attempt to create a more varied scheduling pattern in the hope of unearthing races 784 runtime.Gosched() 785 786 pm.SetTxValidationResult(cc, 1, uint64(txnum), errors.New("")) 787 788 // we yield in an attempt to create a more varied scheduling pattern in the hope of unearthing races 789 runtime.Gosched() 790 791 sp, err := pm.GetValidationParameterForKey(cc, coll, key, 1, 2) 792 assert.Equal(t, protoutil.MarshalOrPanic(spe), sp) 793 assert.NoError(t, err) 794 } 795 } 796 797 runFunctions(t, seed, funcArray...) 798 799 assert.True(t, ms.DoneCalled(), "assert failure occurred with seed %d", seed) 800 }