github.com/lzy4123/fabric@v2.1.1+incompatible/gossip/privdata/dataretriever_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package privdata 8 9 import ( 10 "errors" 11 "testing" 12 13 gossip2 "github.com/hyperledger/fabric-protos-go/gossip" 14 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 15 "github.com/hyperledger/fabric-protos-go/peer" 16 "github.com/hyperledger/fabric-protos-go/transientstore" 17 "github.com/hyperledger/fabric/core/ledger" 18 privdatacommon "github.com/hyperledger/fabric/gossip/privdata/common" 19 "github.com/hyperledger/fabric/gossip/privdata/mocks" 20 "github.com/stretchr/testify/assert" 21 "github.com/stretchr/testify/mock" 22 ) 23 24 /* 25 Test checks following scenario, it tries to obtain private data for 26 given block sequence which is greater than available ledger height, 27 hence data should be looked up directly from transient store 28 */ 29 func TestNewDataRetriever_GetDataFromTransientStore(t *testing.T) { 30 t.Parallel() 31 committer := &mocks.Committer{} 32 33 store := newTransientStore(t) 34 defer store.tearDown() 35 36 namespace := "testChaincodeName1" 37 collectionName := "testCollectionName" 38 txID := "testTxID" 39 40 committer.On("LedgerHeight").Return(uint64(1), nil) 41 42 retriever := NewDataRetriever(store.store, committer) 43 44 store.Persist(txID, 2, &transientstore.TxPvtReadWriteSetWithConfigInfo{ 45 PvtRwset: &rwset.TxPvtReadWriteSet{ 46 DataModel: rwset.TxReadWriteSet_KV, 47 NsPvtRwset: []*rwset.NsPvtReadWriteSet{ 48 pvtReadWriteSet(namespace, collectionName, []byte{1, 2}), 49 pvtReadWriteSet(namespace, collectionName, []byte{3, 4}), 50 }, 51 }, 52 CollectionConfigs: map[string]*peer.CollectionConfigPackage{ 53 namespace: { 54 Config: []*peer.CollectionConfig{ 55 { 56 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 57 StaticCollectionConfig: &peer.StaticCollectionConfig{ 58 Name: collectionName, 59 }, 60 }, 61 }, 62 }, 63 }, 64 }, 65 }) 66 67 // Request digest for private data which is greater than current ledger height 68 // to make it query transient store for missed private data 69 rwSets, _, err := retriever.CollectionRWSet([]*gossip2.PvtDataDigest{{ 70 Namespace: namespace, 71 Collection: collectionName, 72 BlockSeq: 2, 73 TxId: txID, 74 SeqInBlock: 1, 75 }}, 2) 76 77 assertion := assert.New(t) 78 assertion.NoError(err) 79 assertion.NotEmpty(rwSets) 80 dig2pvtRWSet := rwSets[privdatacommon.DigKey{ 81 Namespace: namespace, 82 Collection: collectionName, 83 BlockSeq: 2, 84 TxId: txID, 85 SeqInBlock: 1, 86 }] 87 assertion.NotNil(dig2pvtRWSet) 88 pvtRWSets := dig2pvtRWSet.RWSet 89 assertion.Equal(2, len(pvtRWSets)) 90 91 var mergedRWSet []byte 92 for _, rws := range pvtRWSets { 93 mergedRWSet = append(mergedRWSet, rws...) 94 } 95 96 assertion.Equal([]byte{1, 2, 3, 4}, mergedRWSet) 97 } 98 99 /* 100 Simple test case where available ledger height is greater than 101 requested block sequence and therefore private data will be retrieved 102 from the ledger rather than transient store as data being committed 103 */ 104 func TestNewDataRetriever_GetDataFromLedger(t *testing.T) { 105 t.Parallel() 106 committer := &mocks.Committer{} 107 108 store := newTransientStore(t) 109 defer store.tearDown() 110 111 namespace := "testChaincodeName1" 112 collectionName := "testCollectionName" 113 114 result := []*ledger.TxPvtData{{ 115 WriteSet: &rwset.TxPvtReadWriteSet{ 116 DataModel: rwset.TxReadWriteSet_KV, 117 NsPvtRwset: []*rwset.NsPvtReadWriteSet{ 118 pvtReadWriteSet(namespace, collectionName, []byte{1, 2}), 119 pvtReadWriteSet(namespace, collectionName, []byte{3, 4}), 120 }, 121 }, 122 SeqInBlock: 1, 123 }} 124 125 committer.On("LedgerHeight").Return(uint64(10), nil) 126 committer.On("GetPvtDataByNum", uint64(5), mock.Anything).Return(result, nil) 127 128 historyRetreiver := &mocks.ConfigHistoryRetriever{} 129 historyRetreiver.On("MostRecentCollectionConfigBelow", mock.Anything, namespace).Return(newCollectionConfig(collectionName), nil) 130 committer.On("GetConfigHistoryRetriever").Return(historyRetreiver, nil) 131 132 retriever := NewDataRetriever(store.store, committer) 133 134 // Request digest for private data which is greater than current ledger height 135 // to make it query ledger for missed private data 136 rwSets, _, err := retriever.CollectionRWSet([]*gossip2.PvtDataDigest{{ 137 Namespace: namespace, 138 Collection: collectionName, 139 BlockSeq: uint64(5), 140 TxId: "testTxID", 141 SeqInBlock: 1, 142 }}, uint64(5)) 143 144 assertion := assert.New(t) 145 assertion.NoError(err) 146 assertion.NotEmpty(rwSets) 147 pvtRWSet := rwSets[privdatacommon.DigKey{ 148 Namespace: namespace, 149 Collection: collectionName, 150 BlockSeq: 5, 151 TxId: "testTxID", 152 SeqInBlock: 1, 153 }] 154 assertion.NotEmpty(pvtRWSet) 155 assertion.Equal(2, len(pvtRWSet.RWSet)) 156 157 var mergedRWSet []byte 158 for _, rws := range pvtRWSet.RWSet { 159 mergedRWSet = append(mergedRWSet, rws...) 160 } 161 162 assertion.Equal([]byte{1, 2, 3, 4}, mergedRWSet) 163 } 164 165 func TestNewDataRetriever_FailGetPvtDataFromLedger(t *testing.T) { 166 t.Parallel() 167 committer := &mocks.Committer{} 168 169 store := newTransientStore(t) 170 defer store.tearDown() 171 172 namespace := "testChaincodeName1" 173 collectionName := "testCollectionName" 174 175 committer.On("LedgerHeight").Return(uint64(10), nil) 176 committer.On("GetPvtDataByNum", uint64(5), mock.Anything). 177 Return(nil, errors.New("failing retrieving private data")) 178 179 retriever := NewDataRetriever(store.store, committer) 180 181 // Request digest for private data which is greater than current ledger height 182 // to make it query transient store for missed private data 183 rwSets, _, err := retriever.CollectionRWSet([]*gossip2.PvtDataDigest{{ 184 Namespace: namespace, 185 Collection: collectionName, 186 BlockSeq: uint64(5), 187 TxId: "testTxID", 188 SeqInBlock: 1, 189 }}, uint64(5)) 190 191 assertion := assert.New(t) 192 assertion.Error(err) 193 assertion.Empty(rwSets) 194 } 195 196 func TestNewDataRetriever_GetOnlyRelevantPvtData(t *testing.T) { 197 t.Parallel() 198 committer := &mocks.Committer{} 199 200 store := newTransientStore(t) 201 defer store.tearDown() 202 203 namespace := "testChaincodeName1" 204 collectionName := "testCollectionName" 205 206 result := []*ledger.TxPvtData{{ 207 WriteSet: &rwset.TxPvtReadWriteSet{ 208 DataModel: rwset.TxReadWriteSet_KV, 209 NsPvtRwset: []*rwset.NsPvtReadWriteSet{ 210 pvtReadWriteSet(namespace, collectionName, []byte{1}), 211 pvtReadWriteSet(namespace, collectionName, []byte{2}), 212 pvtReadWriteSet("invalidNamespace", collectionName, []byte{0, 0}), 213 pvtReadWriteSet(namespace, "invalidCollectionName", []byte{0, 0}), 214 }, 215 }, 216 SeqInBlock: 1, 217 }} 218 219 committer.On("LedgerHeight").Return(uint64(10), nil) 220 committer.On("GetPvtDataByNum", uint64(5), mock.Anything).Return(result, nil) 221 historyRetreiver := &mocks.ConfigHistoryRetriever{} 222 historyRetreiver.On("MostRecentCollectionConfigBelow", mock.Anything, namespace).Return(newCollectionConfig(collectionName), nil) 223 committer.On("GetConfigHistoryRetriever").Return(historyRetreiver, nil) 224 225 retriever := NewDataRetriever(store.store, committer) 226 227 // Request digest for private data which is greater than current ledger height 228 // to make it query transient store for missed private data 229 rwSets, _, err := retriever.CollectionRWSet([]*gossip2.PvtDataDigest{{ 230 Namespace: namespace, 231 Collection: collectionName, 232 BlockSeq: uint64(5), 233 TxId: "testTxID", 234 SeqInBlock: 1, 235 }}, 5) 236 237 assertion := assert.New(t) 238 assertion.NoError(err) 239 assertion.NotEmpty(rwSets) 240 pvtRWSet := rwSets[privdatacommon.DigKey{ 241 Namespace: namespace, 242 Collection: collectionName, 243 BlockSeq: 5, 244 TxId: "testTxID", 245 SeqInBlock: 1, 246 }] 247 assertion.NotEmpty(pvtRWSet) 248 assertion.Equal(2, len(pvtRWSet.RWSet)) 249 250 var mergedRWSet []byte 251 for _, rws := range pvtRWSet.RWSet { 252 mergedRWSet = append(mergedRWSet, rws...) 253 } 254 255 assertion.Equal([]byte{1, 2}, mergedRWSet) 256 } 257 258 func TestNewDataRetriever_GetMultipleDigests(t *testing.T) { 259 t.Parallel() 260 committer := &mocks.Committer{} 261 262 store := newTransientStore(t) 263 defer store.tearDown() 264 265 ns1, ns2 := "testChaincodeName1", "testChaincodeName2" 266 col1, col2 := "testCollectionName1", "testCollectionName2" 267 268 result := []*ledger.TxPvtData{ 269 { 270 WriteSet: &rwset.TxPvtReadWriteSet{ 271 DataModel: rwset.TxReadWriteSet_KV, 272 NsPvtRwset: []*rwset.NsPvtReadWriteSet{ 273 pvtReadWriteSet(ns1, col1, []byte{1}), 274 pvtReadWriteSet(ns1, col1, []byte{2}), 275 pvtReadWriteSet("invalidNamespace", col1, []byte{0, 0}), 276 pvtReadWriteSet(ns1, "invalidCollectionName", []byte{0, 0}), 277 }, 278 }, 279 SeqInBlock: 1, 280 }, 281 { 282 WriteSet: &rwset.TxPvtReadWriteSet{ 283 DataModel: rwset.TxReadWriteSet_KV, 284 NsPvtRwset: []*rwset.NsPvtReadWriteSet{ 285 pvtReadWriteSet(ns2, col2, []byte{3}), 286 pvtReadWriteSet(ns2, col2, []byte{4}), 287 pvtReadWriteSet("invalidNamespace", col2, []byte{0, 0}), 288 pvtReadWriteSet(ns2, "invalidCollectionName", []byte{0, 0}), 289 }, 290 }, 291 SeqInBlock: 2, 292 }, 293 { 294 WriteSet: &rwset.TxPvtReadWriteSet{ 295 DataModel: rwset.TxReadWriteSet_KV, 296 NsPvtRwset: []*rwset.NsPvtReadWriteSet{ 297 pvtReadWriteSet(ns1, col1, []byte{5}), 298 pvtReadWriteSet(ns2, col2, []byte{6}), 299 pvtReadWriteSet("invalidNamespace", col2, []byte{0, 0}), 300 pvtReadWriteSet(ns2, "invalidCollectionName", []byte{0, 0}), 301 }, 302 }, 303 SeqInBlock: 3, 304 }, 305 } 306 307 committer.On("LedgerHeight").Return(uint64(10), nil) 308 committer.On("GetPvtDataByNum", uint64(5), mock.Anything).Return(result, nil) 309 historyRetreiver := &mocks.ConfigHistoryRetriever{} 310 historyRetreiver.On("MostRecentCollectionConfigBelow", mock.Anything, ns1).Return(newCollectionConfig(col1), nil) 311 historyRetreiver.On("MostRecentCollectionConfigBelow", mock.Anything, ns2).Return(newCollectionConfig(col2), nil) 312 committer.On("GetConfigHistoryRetriever").Return(historyRetreiver, nil) 313 314 retriever := NewDataRetriever(store.store, committer) 315 316 // Request digest for private data which is greater than current ledger height 317 // to make it query transient store for missed private data 318 rwSets, _, err := retriever.CollectionRWSet([]*gossip2.PvtDataDigest{{ 319 Namespace: ns1, 320 Collection: col1, 321 BlockSeq: uint64(5), 322 TxId: "testTxID", 323 SeqInBlock: 1, 324 }, { 325 Namespace: ns2, 326 Collection: col2, 327 BlockSeq: uint64(5), 328 TxId: "testTxID", 329 SeqInBlock: 2, 330 }}, 5) 331 332 assertion := assert.New(t) 333 assertion.NoError(err) 334 assertion.NotEmpty(rwSets) 335 assertion.Equal(2, len(rwSets)) 336 337 pvtRWSet := rwSets[privdatacommon.DigKey{ 338 Namespace: ns1, 339 Collection: col1, 340 BlockSeq: 5, 341 TxId: "testTxID", 342 SeqInBlock: 1, 343 }] 344 assertion.NotEmpty(pvtRWSet) 345 assertion.Equal(2, len(pvtRWSet.RWSet)) 346 347 var mergedRWSet []byte 348 for _, rws := range pvtRWSet.RWSet { 349 mergedRWSet = append(mergedRWSet, rws...) 350 } 351 352 pvtRWSet = rwSets[privdatacommon.DigKey{ 353 Namespace: ns2, 354 Collection: col2, 355 BlockSeq: 5, 356 TxId: "testTxID", 357 SeqInBlock: 2, 358 }] 359 assertion.NotEmpty(pvtRWSet) 360 assertion.Equal(2, len(pvtRWSet.RWSet)) 361 for _, rws := range pvtRWSet.RWSet { 362 mergedRWSet = append(mergedRWSet, rws...) 363 } 364 365 assertion.Equal([]byte{1, 2, 3, 4}, mergedRWSet) 366 } 367 368 func TestNewDataRetriever_EmptyWriteSet(t *testing.T) { 369 t.Parallel() 370 committer := &mocks.Committer{} 371 372 store := newTransientStore(t) 373 defer store.tearDown() 374 375 ns1 := "testChaincodeName1" 376 col1 := "testCollectionName1" 377 378 result := []*ledger.TxPvtData{ 379 { 380 SeqInBlock: 1, 381 }, 382 } 383 384 committer.On("LedgerHeight").Return(uint64(10), nil) 385 committer.On("GetPvtDataByNum", uint64(5), mock.Anything).Return(result, nil) 386 historyRetreiver := &mocks.ConfigHistoryRetriever{} 387 historyRetreiver.On("MostRecentCollectionConfigBelow", mock.Anything, ns1).Return(newCollectionConfig(col1), nil) 388 committer.On("GetConfigHistoryRetriever").Return(historyRetreiver, nil) 389 390 retriever := NewDataRetriever(store.store, committer) 391 392 rwSets, _, err := retriever.CollectionRWSet([]*gossip2.PvtDataDigest{{ 393 Namespace: ns1, 394 Collection: col1, 395 BlockSeq: uint64(5), 396 TxId: "testTxID", 397 SeqInBlock: 1, 398 }}, 5) 399 400 assertion := assert.New(t) 401 assertion.NoError(err) 402 assertion.NotEmpty(rwSets) 403 404 pvtRWSet := rwSets[privdatacommon.DigKey{ 405 Namespace: ns1, 406 Collection: col1, 407 BlockSeq: 5, 408 TxId: "testTxID", 409 SeqInBlock: 1, 410 }] 411 assertion.NotEmpty(pvtRWSet) 412 assertion.Empty(pvtRWSet.RWSet) 413 414 } 415 416 func TestNewDataRetriever_FailedObtainConfigHistoryRetriever(t *testing.T) { 417 t.Parallel() 418 committer := &mocks.Committer{} 419 420 store := newTransientStore(t) 421 defer store.tearDown() 422 423 ns1 := "testChaincodeName1" 424 col1 := "testCollectionName1" 425 426 result := []*ledger.TxPvtData{ 427 { 428 WriteSet: &rwset.TxPvtReadWriteSet{ 429 DataModel: rwset.TxReadWriteSet_KV, 430 NsPvtRwset: []*rwset.NsPvtReadWriteSet{ 431 pvtReadWriteSet(ns1, col1, []byte{1}), 432 pvtReadWriteSet(ns1, col1, []byte{2}), 433 }, 434 }, 435 SeqInBlock: 1, 436 }, 437 } 438 439 committer.On("LedgerHeight").Return(uint64(10), nil) 440 committer.On("GetPvtDataByNum", uint64(5), mock.Anything).Return(result, nil) 441 committer.On("GetConfigHistoryRetriever").Return(nil, errors.New("failed to obtain ConfigHistoryRetriever")) 442 443 retriever := NewDataRetriever(store.store, committer) 444 445 _, _, err := retriever.CollectionRWSet([]*gossip2.PvtDataDigest{{ 446 Namespace: ns1, 447 Collection: col1, 448 BlockSeq: uint64(5), 449 TxId: "testTxID", 450 SeqInBlock: 1, 451 }}, 5) 452 453 assertion := assert.New(t) 454 assertion.Contains(err.Error(), "failed to obtain ConfigHistoryRetriever") 455 } 456 457 func TestNewDataRetriever_NoCollectionConfig(t *testing.T) { 458 t.Parallel() 459 committer := &mocks.Committer{} 460 461 store := newTransientStore(t) 462 defer store.tearDown() 463 464 ns1, ns2 := "testChaincodeName1", "testChaincodeName2" 465 col1, col2 := "testCollectionName1", "testCollectionName2" 466 467 result := []*ledger.TxPvtData{ 468 { 469 WriteSet: &rwset.TxPvtReadWriteSet{ 470 DataModel: rwset.TxReadWriteSet_KV, 471 NsPvtRwset: []*rwset.NsPvtReadWriteSet{ 472 pvtReadWriteSet(ns1, col1, []byte{1}), 473 pvtReadWriteSet(ns1, col1, []byte{2}), 474 }, 475 }, 476 SeqInBlock: 1, 477 }, 478 { 479 WriteSet: &rwset.TxPvtReadWriteSet{ 480 DataModel: rwset.TxReadWriteSet_KV, 481 NsPvtRwset: []*rwset.NsPvtReadWriteSet{ 482 pvtReadWriteSet(ns2, col2, []byte{3}), 483 pvtReadWriteSet(ns2, col2, []byte{4}), 484 }, 485 }, 486 SeqInBlock: 2, 487 }, 488 } 489 490 committer.On("LedgerHeight").Return(uint64(10), nil) 491 committer.On("GetPvtDataByNum", uint64(5), mock.Anything).Return(result, nil) 492 historyRetreiver := &mocks.ConfigHistoryRetriever{} 493 historyRetreiver.On("MostRecentCollectionConfigBelow", mock.Anything, ns1). 494 Return(newCollectionConfig(col1), errors.New("failed to obtain collection config")) 495 historyRetreiver.On("MostRecentCollectionConfigBelow", mock.Anything, ns2). 496 Return(nil, nil) 497 committer.On("GetConfigHistoryRetriever").Return(historyRetreiver, nil) 498 499 retriever := NewDataRetriever(store.store, committer) 500 assertion := assert.New(t) 501 502 _, _, err := retriever.CollectionRWSet([]*gossip2.PvtDataDigest{{ 503 Namespace: ns1, 504 Collection: col1, 505 BlockSeq: uint64(5), 506 TxId: "testTxID", 507 SeqInBlock: 1, 508 }}, 5) 509 assertion.Error(err) 510 assertion.Contains(err.Error(), "cannot find recent collection config update below block sequence") 511 512 _, _, err = retriever.CollectionRWSet([]*gossip2.PvtDataDigest{{ 513 Namespace: ns2, 514 Collection: col2, 515 BlockSeq: uint64(5), 516 TxId: "testTxID", 517 SeqInBlock: 2, 518 }}, 5) 519 assertion.Error(err) 520 assertion.Contains(err.Error(), "no collection config update below block sequence") 521 } 522 523 func TestNewDataRetriever_FailedGetLedgerHeight(t *testing.T) { 524 t.Parallel() 525 committer := &mocks.Committer{} 526 527 store := newTransientStore(t) 528 defer store.tearDown() 529 530 ns1 := "testChaincodeName1" 531 col1 := "testCollectionName1" 532 533 committer.On("LedgerHeight").Return(uint64(0), errors.New("failed to read ledger height")) 534 retriever := NewDataRetriever(store.store, committer) 535 536 _, _, err := retriever.CollectionRWSet([]*gossip2.PvtDataDigest{{ 537 Namespace: ns1, 538 Collection: col1, 539 BlockSeq: uint64(5), 540 TxId: "testTxID", 541 SeqInBlock: 1, 542 }}, 5) 543 544 assertion := assert.New(t) 545 assertion.Error(err) 546 assertion.Contains(err.Error(), "failed to read ledger height") 547 } 548 549 func TestNewDataRetriever_EmptyPvtRWSetInTransientStore(t *testing.T) { 550 t.Parallel() 551 committer := &mocks.Committer{} 552 553 store := newTransientStore(t) 554 defer store.tearDown() 555 556 namespace := "testChaincodeName1" 557 collectionName := "testCollectionName" 558 559 committer.On("LedgerHeight").Return(uint64(1), nil) 560 561 retriever := NewDataRetriever(store.store, committer) 562 563 rwSets, _, err := retriever.CollectionRWSet([]*gossip2.PvtDataDigest{{ 564 Namespace: namespace, 565 Collection: collectionName, 566 BlockSeq: 2, 567 TxId: "testTxID", 568 SeqInBlock: 1, 569 }}, 2) 570 571 assertion := assert.New(t) 572 assertion.NoError(err) 573 assertion.NotEmpty(rwSets) 574 assertion.Empty(rwSets[privdatacommon.DigKey{ 575 Namespace: namespace, 576 Collection: collectionName, 577 BlockSeq: 2, 578 TxId: "testTxID", 579 SeqInBlock: 1, 580 }]) 581 } 582 583 func newCollectionConfig(collectionName string) *ledger.CollectionConfigInfo { 584 return &ledger.CollectionConfigInfo{ 585 CollectionConfig: &peer.CollectionConfigPackage{ 586 Config: []*peer.CollectionConfig{ 587 { 588 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 589 StaticCollectionConfig: &peer.StaticCollectionConfig{ 590 Name: collectionName, 591 }, 592 }, 593 }, 594 }, 595 }, 596 } 597 } 598 599 func pvtReadWriteSet(ns string, collectionName string, data []byte) *rwset.NsPvtReadWriteSet { 600 return &rwset.NsPvtReadWriteSet{ 601 Namespace: ns, 602 CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{{ 603 CollectionName: collectionName, 604 Rwset: data, 605 }}, 606 } 607 }