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