github.com/lzy4123/fabric@v2.1.1+incompatible/gossip/privdata/pull_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 "bytes" 11 "crypto/rand" 12 "io/ioutil" 13 "os" 14 "sync" 15 "testing" 16 17 pb "github.com/golang/protobuf/proto" 18 proto "github.com/hyperledger/fabric-protos-go/gossip" 19 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 20 "github.com/hyperledger/fabric-protos-go/peer" 21 "github.com/hyperledger/fabric/common/metrics/disabled" 22 "github.com/hyperledger/fabric/core/common/privdata" 23 "github.com/hyperledger/fabric/core/ledger" 24 "github.com/hyperledger/fabric/core/transientstore" 25 "github.com/hyperledger/fabric/gossip/api" 26 "github.com/hyperledger/fabric/gossip/comm" 27 "github.com/hyperledger/fabric/gossip/common" 28 "github.com/hyperledger/fabric/gossip/discovery" 29 "github.com/hyperledger/fabric/gossip/filter" 30 "github.com/hyperledger/fabric/gossip/metrics" 31 gmetricsmocks "github.com/hyperledger/fabric/gossip/metrics/mocks" 32 privdatacommon "github.com/hyperledger/fabric/gossip/privdata/common" 33 "github.com/hyperledger/fabric/gossip/privdata/mocks" 34 "github.com/hyperledger/fabric/gossip/protoext" 35 "github.com/hyperledger/fabric/gossip/util" 36 "github.com/hyperledger/fabric/protoutil" 37 "github.com/pkg/errors" 38 "github.com/stretchr/testify/assert" 39 "github.com/stretchr/testify/mock" 40 ) 41 42 func init() { 43 policy2Filter = make(map[privdata.CollectionAccessPolicy]privdata.Filter) 44 } 45 46 // protoMatcher is used to test that a slice of protos equals another slice of protos. 47 // This is needed because in general reflect.Equal(proto1, proto1) may not be true. 48 func protoMatcher(pvds ...*proto.PvtDataDigest) func([]*proto.PvtDataDigest) bool { 49 return func(ipvds []*proto.PvtDataDigest) bool { 50 if len(pvds) != len(ipvds) { 51 return false 52 } 53 54 for i, pvd := range pvds { 55 if !pb.Equal(pvd, ipvds[i]) { 56 return false 57 } 58 } 59 60 return true 61 } 62 } 63 64 var policyLock sync.Mutex 65 var policy2Filter map[privdata.CollectionAccessPolicy]privdata.Filter 66 67 type mockCollectionStore struct { 68 m map[string]*mockCollectionAccess 69 accessFilter privdata.Filter 70 } 71 72 func newCollectionStore() *mockCollectionStore { 73 return &mockCollectionStore{ 74 m: make(map[string]*mockCollectionAccess), 75 accessFilter: nil, 76 } 77 } 78 79 func (cs *mockCollectionStore) withPolicy(collection string, btl uint64) *mockCollectionAccess { 80 coll := &mockCollectionAccess{cs: cs, btl: btl} 81 cs.m[collection] = coll 82 return coll 83 } 84 85 func (cs *mockCollectionStore) withAccessFilter(filter privdata.Filter) *mockCollectionStore { 86 cs.accessFilter = filter 87 return cs 88 } 89 90 func (cs mockCollectionStore) RetrieveCollectionAccessPolicy(cc privdata.CollectionCriteria) (privdata.CollectionAccessPolicy, error) { 91 return cs.m[cc.Collection], nil 92 } 93 94 func (cs mockCollectionStore) RetrieveCollection(privdata.CollectionCriteria) (privdata.Collection, error) { 95 panic("implement me") 96 } 97 98 func (cs mockCollectionStore) RetrieveCollectionConfig(privdata.CollectionCriteria) (*peer.StaticCollectionConfig, error) { 99 panic("implement me") 100 } 101 102 func (cs mockCollectionStore) RetrieveCollectionConfigPackage(privdata.CollectionCriteria) (*peer.CollectionConfigPackage, error) { 103 panic("implement me") 104 } 105 106 func (cs mockCollectionStore) RetrieveCollectionPersistenceConfigs(cc privdata.CollectionCriteria) (privdata.CollectionPersistenceConfigs, error) { 107 return cs.m[cc.Collection], nil 108 } 109 110 func (cs mockCollectionStore) RetrieveReadWritePermission(cc privdata.CollectionCriteria, sp *peer.SignedProposal, qe ledger.QueryExecutor) (bool, bool, error) { 111 panic("implement me") 112 } 113 114 func (cs mockCollectionStore) AccessFilter(channelName string, collectionPolicyConfig *peer.CollectionPolicyConfig) (privdata.Filter, error) { 115 if cs.accessFilter != nil { 116 return cs.accessFilter, nil 117 } 118 panic("implement me") 119 } 120 121 type mockCollectionAccess struct { 122 cs *mockCollectionStore 123 btl uint64 124 } 125 126 func (mc *mockCollectionAccess) BlockToLive() uint64 { 127 return mc.btl 128 } 129 130 func (mc *mockCollectionAccess) thatMapsTo(peers ...string) *mockCollectionStore { 131 policyLock.Lock() 132 defer policyLock.Unlock() 133 policy2Filter[mc] = func(sd protoutil.SignedData) bool { 134 for _, peer := range peers { 135 if bytes.Equal(sd.Identity, []byte(peer)) { 136 return true 137 } 138 } 139 return false 140 } 141 return mc.cs 142 } 143 144 func (mc *mockCollectionAccess) MemberOrgs() map[string]struct{} { 145 return nil 146 } 147 148 func (mc *mockCollectionAccess) AccessFilter() privdata.Filter { 149 policyLock.Lock() 150 defer policyLock.Unlock() 151 return policy2Filter[mc] 152 } 153 154 func (mc *mockCollectionAccess) RequiredPeerCount() int { 155 return 0 156 } 157 158 func (mc *mockCollectionAccess) MaximumPeerCount() int { 159 return 0 160 } 161 162 func (mc *mockCollectionAccess) IsMemberOnlyRead() bool { 163 return false 164 } 165 166 func (mc *mockCollectionAccess) IsMemberOnlyWrite() bool { 167 return false 168 } 169 170 type dataRetrieverMock struct { 171 mock.Mock 172 } 173 174 func (dr *dataRetrieverMock) CollectionRWSet(dig []*proto.PvtDataDigest, blockNum uint64) (Dig2PvtRWSetWithConfig, bool, error) { 175 args := dr.Called(dig, blockNum) 176 return args.Get(0).(Dig2PvtRWSetWithConfig), args.Bool(1), args.Error(2) 177 } 178 179 type receivedMsg struct { 180 responseChan chan protoext.ReceivedMessage 181 *comm.RemotePeer 182 *protoext.SignedGossipMessage 183 } 184 185 func (msg *receivedMsg) Ack(_ error) { 186 187 } 188 189 func (msg *receivedMsg) Respond(message *proto.GossipMessage) { 190 m, _ := protoext.NoopSign(message) 191 msg.responseChan <- &receivedMsg{SignedGossipMessage: m, RemotePeer: &comm.RemotePeer{}} 192 } 193 194 func (msg *receivedMsg) GetGossipMessage() *protoext.SignedGossipMessage { 195 return msg.SignedGossipMessage 196 } 197 198 func (msg *receivedMsg) GetSourceEnvelope() *proto.Envelope { 199 panic("implement me") 200 } 201 202 func (msg *receivedMsg) GetConnectionInfo() *protoext.ConnectionInfo { 203 return &protoext.ConnectionInfo{ 204 Identity: api.PeerIdentityType(msg.RemotePeer.PKIID), 205 Auth: &protoext.AuthInfo{ 206 SignedData: []byte{}, 207 Signature: []byte{}, 208 }, 209 } 210 } 211 212 type mockGossip struct { 213 mock.Mock 214 msgChan chan protoext.ReceivedMessage 215 id *comm.RemotePeer 216 network *gossipNetwork 217 } 218 219 func newMockGossip(id *comm.RemotePeer) *mockGossip { 220 return &mockGossip{ 221 msgChan: make(chan protoext.ReceivedMessage), 222 id: id, 223 } 224 } 225 226 func (g *mockGossip) PeerFilter(channel common.ChannelID, messagePredicate api.SubChannelSelectionCriteria) (filter.RoutingFilter, error) { 227 for _, call := range g.Mock.ExpectedCalls { 228 if call.Method == "PeerFilter" { 229 args := g.Called(channel, messagePredicate) 230 if args.Get(1) != nil { 231 return nil, args.Get(1).(error) 232 } 233 return args.Get(0).(filter.RoutingFilter), nil 234 } 235 } 236 return func(member discovery.NetworkMember) bool { 237 return messagePredicate(api.PeerSignature{ 238 PeerIdentity: api.PeerIdentityType(member.PKIid), 239 }) 240 }, nil 241 } 242 243 func (g *mockGossip) Send(msg *proto.GossipMessage, peers ...*comm.RemotePeer) { 244 sMsg, _ := protoext.NoopSign(msg) 245 for _, peer := range g.network.peers { 246 if bytes.Equal(peer.id.PKIID, peers[0].PKIID) { 247 peer.msgChan <- &receivedMsg{ 248 RemotePeer: g.id, 249 SignedGossipMessage: sMsg, 250 responseChan: g.msgChan, 251 } 252 return 253 } 254 } 255 } 256 257 func (g *mockGossip) PeersOfChannel(common.ChannelID) []discovery.NetworkMember { 258 return g.Called().Get(0).([]discovery.NetworkMember) 259 } 260 261 func (g *mockGossip) Accept(acceptor common.MessageAcceptor, passThrough bool) (<-chan *proto.GossipMessage, <-chan protoext.ReceivedMessage) { 262 return nil, g.msgChan 263 } 264 265 type peerData struct { 266 id string 267 ledgerHeight uint64 268 } 269 270 func membership(knownPeers ...peerData) []discovery.NetworkMember { 271 var peers []discovery.NetworkMember 272 for _, peer := range knownPeers { 273 peers = append(peers, discovery.NetworkMember{ 274 Endpoint: peer.id, 275 PKIid: common.PKIidType(peer.id), 276 Properties: &proto.Properties{ 277 LedgerHeight: peer.ledgerHeight, 278 }, 279 }) 280 } 281 return peers 282 } 283 284 type gossipNetwork struct { 285 peers []*mockGossip 286 } 287 288 func (gn *gossipNetwork) newPullerWithMetrics(metrics *metrics.PrivdataMetrics, id string, ps privdata.CollectionStore, 289 factory CollectionAccessFactory, knownMembers ...discovery.NetworkMember) *puller { 290 g := newMockGossip(&comm.RemotePeer{PKIID: common.PKIidType(id), Endpoint: id}) 291 g.network = gn 292 g.On("PeersOfChannel", mock.Anything).Return(knownMembers) 293 294 p := NewPuller(metrics, ps, g, &dataRetrieverMock{}, factory, "A", 10) 295 gn.peers = append(gn.peers, g) 296 return p 297 } 298 299 func (gn *gossipNetwork) newPuller(id string, ps privdata.CollectionStore, factory CollectionAccessFactory, 300 knownMembers ...discovery.NetworkMember) *puller { 301 metrics := metrics.NewGossipMetrics(&disabled.Provider{}).PrivdataMetrics 302 return gn.newPullerWithMetrics(metrics, id, ps, factory, knownMembers...) 303 } 304 305 func newPRWSet() []util.PrivateRWSet { 306 b1 := make([]byte, 10) 307 b2 := make([]byte, 10) 308 rand.Read(b1) 309 rand.Read(b2) 310 return []util.PrivateRWSet{util.PrivateRWSet(b1), util.PrivateRWSet(b2)} 311 } 312 313 func TestPullerFromOnly1Peer(t *testing.T) { 314 t.Parallel() 315 // Scenario: p1 pulls from p2 and not from p3 316 // and succeeds - p1 asks from p2 (and not from p3!) for the 317 // expected digest 318 gn := &gossipNetwork{} 319 policyStore := newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2") 320 factoryMock1 := &mocks.CollectionAccessFactory{} 321 policyMock1 := &mocks.CollectionAccessPolicy{} 322 Setup(policyMock1, 1, 2, func(data protoutil.SignedData) bool { 323 return bytes.Equal(data.Identity, []byte("p2")) 324 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 325 factoryMock1.On("AccessPolicy", mock.Anything, mock.Anything).Return(policyMock1, nil) 326 p1 := gn.newPuller("p1", policyStore, factoryMock1, membership(peerData{"p2", uint64(1)}, peerData{"p3", uint64(1)})...) 327 328 p2TransientStore := &util.PrivateRWSetWithConfig{ 329 RWSet: newPRWSet(), 330 CollectionConfig: &peer.CollectionConfig{ 331 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 332 StaticCollectionConfig: &peer.StaticCollectionConfig{ 333 Name: "col1", 334 }, 335 }, 336 }, 337 } 338 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p1") 339 factoryMock2 := &mocks.CollectionAccessFactory{} 340 policyMock2 := &mocks.CollectionAccessPolicy{} 341 Setup(policyMock2, 1, 2, func(data protoutil.SignedData) bool { 342 return bytes.Equal(data.Identity, []byte("p1")) 343 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 344 factoryMock2.On("AccessPolicy", mock.Anything, mock.Anything).Return(policyMock2, nil) 345 346 p2 := gn.newPuller("p2", policyStore, factoryMock2) 347 dig := &proto.PvtDataDigest{ 348 TxId: "txID1", 349 Collection: "col1", 350 Namespace: "ns1", 351 } 352 353 store := Dig2PvtRWSetWithConfig{ 354 privdatacommon.DigKey{ 355 TxId: "txID1", 356 Collection: "col1", 357 Namespace: "ns1", 358 }: p2TransientStore, 359 } 360 361 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), uint64(0)).Return(store, true, nil) 362 363 factoryMock3 := &mocks.CollectionAccessFactory{} 364 policyMock3 := &mocks.CollectionAccessPolicy{} 365 Setup(policyMock3, 1, 2, func(data protoutil.SignedData) bool { 366 return false 367 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 368 factoryMock3.On("AccessPolicy", mock.Anything, mock.Anything).Return(policyMock3, nil) 369 370 p3 := gn.newPuller("p3", newCollectionStore(), factoryMock3) 371 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), uint64(0)).Run(func(_ mock.Arguments) { 372 t.Fatal("p3 shouldn't have been selected for pull") 373 }) 374 375 dasf := &digestsAndSourceFactory{} 376 377 fetchedMessages, err := p1.fetch(dasf.mapDigest(toDigKey(dig)).toSources().create()) 378 rws1 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[0]) 379 rws2 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[1]) 380 fetched := []util.PrivateRWSet{rws1, rws2} 381 assert.NoError(t, err) 382 assert.Equal(t, p2TransientStore.RWSet, fetched) 383 } 384 385 func TestPullerDataNotAvailable(t *testing.T) { 386 t.Parallel() 387 // Scenario: p1 pulls from p2 and not from p3 388 // but the data in p2 doesn't exist 389 gn := &gossipNetwork{} 390 policyStore := newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2") 391 factoryMock := &mocks.CollectionAccessFactory{} 392 factoryMock.On("AccessPolicy", mock.Anything, mock.Anything).Return(&mocks.CollectionAccessPolicy{}, nil) 393 394 p1 := gn.newPuller("p1", policyStore, factoryMock, membership(peerData{"p2", uint64(1)}, peerData{"p3", uint64(1)})...) 395 396 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p1") 397 p2 := gn.newPuller("p2", policyStore, factoryMock) 398 dig := &proto.PvtDataDigest{ 399 TxId: "txID1", 400 Collection: "col1", 401 Namespace: "ns1", 402 } 403 404 store := Dig2PvtRWSetWithConfig{ 405 privdatacommon.DigKey{ 406 TxId: "txID1", 407 Collection: "col1", 408 Namespace: "ns1", 409 }: &util.PrivateRWSetWithConfig{ 410 RWSet: []util.PrivateRWSet{}, 411 }, 412 } 413 414 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), mock.Anything).Return(store, true, nil) 415 416 p3 := gn.newPuller("p3", newCollectionStore(), factoryMock) 417 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), mock.Anything).Run(func(_ mock.Arguments) { 418 t.Fatal("p3 shouldn't have been selected for pull") 419 }) 420 421 dasf := &digestsAndSourceFactory{} 422 fetchedMessages, err := p1.fetch(dasf.mapDigest(toDigKey(dig)).toSources().create()) 423 assert.Empty(t, fetchedMessages.AvailableElements) 424 assert.NoError(t, err) 425 } 426 427 func TestPullerNoPeersKnown(t *testing.T) { 428 t.Parallel() 429 // Scenario: p1 doesn't know any peer and therefore fails fetching 430 gn := &gossipNetwork{} 431 policyStore := newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2", "p3") 432 factoryMock := &mocks.CollectionAccessFactory{} 433 factoryMock.On("AccessPolicy", mock.Anything, mock.Anything).Return(&mocks.CollectionAccessPolicy{}, nil) 434 435 p1 := gn.newPuller("p1", policyStore, factoryMock) 436 dasf := &digestsAndSourceFactory{} 437 d2s := dasf.mapDigest(&privdatacommon.DigKey{Collection: "col1", TxId: "txID1", Namespace: "ns1"}).toSources().create() 438 fetchedMessages, err := p1.fetch(d2s) 439 assert.Empty(t, fetchedMessages) 440 assert.Error(t, err) 441 assert.Contains(t, err.Error(), "Empty membership") 442 } 443 444 func TestPullPeerFilterError(t *testing.T) { 445 t.Parallel() 446 // Scenario: p1 attempts to fetch for the wrong channel 447 gn := &gossipNetwork{} 448 policyStore := newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2") 449 factoryMock := &mocks.CollectionAccessFactory{} 450 factoryMock.On("AccessPolicy", mock.Anything, mock.Anything).Return(&mocks.CollectionAccessPolicy{}, nil) 451 452 p1 := gn.newPuller("p1", policyStore, factoryMock) 453 gn.peers[0].On("PeerFilter", mock.Anything, mock.Anything).Return(nil, errors.New("Failed obtaining filter")) 454 dasf := &digestsAndSourceFactory{} 455 d2s := dasf.mapDigest(&privdatacommon.DigKey{Collection: "col1", TxId: "txID1", Namespace: "ns1"}).toSources().create() 456 fetchedMessages, err := p1.fetch(d2s) 457 assert.Error(t, err) 458 assert.Contains(t, err.Error(), "Failed obtaining filter") 459 assert.Empty(t, fetchedMessages) 460 } 461 462 func TestPullerPeerNotEligible(t *testing.T) { 463 t.Parallel() 464 // Scenario: p1 pulls from p2 or from p3 465 // but it's not eligible for pulling data from p2 or from p3 466 gn := &gossipNetwork{} 467 policyStore := newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2", "p3") 468 factoryMock1 := &mocks.CollectionAccessFactory{} 469 accessPolicyMock1 := &mocks.CollectionAccessPolicy{} 470 Setup(accessPolicyMock1, 1, 2, func(data protoutil.SignedData) bool { 471 return bytes.Equal(data.Identity, []byte("p2")) || bytes.Equal(data.Identity, []byte("p3")) 472 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 473 factoryMock1.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock1, nil) 474 475 p1 := gn.newPuller("p1", policyStore, factoryMock1, membership(peerData{"p2", uint64(1)}, peerData{"p3", uint64(1)})...) 476 477 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2") 478 factoryMock2 := &mocks.CollectionAccessFactory{} 479 accessPolicyMock2 := &mocks.CollectionAccessPolicy{} 480 Setup(accessPolicyMock2, 1, 2, func(data protoutil.SignedData) bool { 481 return bytes.Equal(data.Identity, []byte("p2")) 482 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 483 factoryMock2.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock2, nil) 484 485 p2 := gn.newPuller("p2", policyStore, factoryMock2) 486 487 dig := &proto.PvtDataDigest{ 488 TxId: "txID1", 489 Collection: "col1", 490 Namespace: "ns1", 491 } 492 493 store := Dig2PvtRWSetWithConfig{ 494 privdatacommon.DigKey{ 495 TxId: "txID1", 496 Collection: "col1", 497 Namespace: "ns1", 498 }: &util.PrivateRWSetWithConfig{ 499 RWSet: newPRWSet(), 500 CollectionConfig: &peer.CollectionConfig{ 501 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 502 StaticCollectionConfig: &peer.StaticCollectionConfig{ 503 Name: "col1", 504 }, 505 }, 506 }, 507 }, 508 } 509 510 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), mock.Anything).Return(store, true, nil) 511 512 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p3") 513 factoryMock3 := &mocks.CollectionAccessFactory{} 514 accessPolicyMock3 := &mocks.CollectionAccessPolicy{} 515 Setup(accessPolicyMock3, 1, 2, func(data protoutil.SignedData) bool { 516 return bytes.Equal(data.Identity, []byte("p3")) 517 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 518 factoryMock3.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock1, nil) 519 520 p3 := gn.newPuller("p3", policyStore, factoryMock3) 521 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), mock.Anything).Return(store, true, nil) 522 dasf := &digestsAndSourceFactory{} 523 d2s := dasf.mapDigest(&privdatacommon.DigKey{Collection: "col1", TxId: "txID1", Namespace: "ns1"}).toSources().create() 524 fetchedMessages, err := p1.fetch(d2s) 525 assert.Empty(t, fetchedMessages.AvailableElements) 526 assert.NoError(t, err) 527 } 528 529 func TestPullerDifferentPeersDifferentCollections(t *testing.T) { 530 t.Parallel() 531 // Scenario: p1 pulls from p2 and from p3 532 // and each has different collections 533 gn := &gossipNetwork{} 534 factoryMock1 := &mocks.CollectionAccessFactory{} 535 accessPolicyMock1 := &mocks.CollectionAccessPolicy{} 536 Setup(accessPolicyMock1, 1, 2, func(data protoutil.SignedData) bool { 537 return bytes.Equal(data.Identity, []byte("p2")) || bytes.Equal(data.Identity, []byte("p3")) 538 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 539 factoryMock1.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock1, nil) 540 541 policyStore := newCollectionStore().withPolicy("col2", uint64(100)).thatMapsTo("p2").withPolicy("col3", uint64(100)).thatMapsTo("p3") 542 p1 := gn.newPuller("p1", policyStore, factoryMock1, membership(peerData{"p2", uint64(1)}, peerData{"p3", uint64(1)})...) 543 544 p2TransientStore := &util.PrivateRWSetWithConfig{ 545 RWSet: newPRWSet(), 546 CollectionConfig: &peer.CollectionConfig{ 547 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 548 StaticCollectionConfig: &peer.StaticCollectionConfig{ 549 Name: "col2", 550 }, 551 }, 552 }, 553 } 554 555 policyStore = newCollectionStore().withPolicy("col2", uint64(100)).thatMapsTo("p1") 556 factoryMock2 := &mocks.CollectionAccessFactory{} 557 accessPolicyMock2 := &mocks.CollectionAccessPolicy{} 558 Setup(accessPolicyMock2, 1, 2, func(data protoutil.SignedData) bool { 559 return bytes.Equal(data.Identity, []byte("p1")) 560 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 561 factoryMock2.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock2, nil) 562 563 p2 := gn.newPuller("p2", policyStore, factoryMock2) 564 dig1 := &proto.PvtDataDigest{ 565 TxId: "txID1", 566 Collection: "col2", 567 Namespace: "ns1", 568 } 569 570 store1 := Dig2PvtRWSetWithConfig{ 571 privdatacommon.DigKey{ 572 TxId: "txID1", 573 Collection: "col2", 574 Namespace: "ns1", 575 }: p2TransientStore, 576 } 577 578 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig1)), mock.Anything).Return(store1, true, nil) 579 580 p3TransientStore := &util.PrivateRWSetWithConfig{ 581 RWSet: newPRWSet(), 582 CollectionConfig: &peer.CollectionConfig{ 583 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 584 StaticCollectionConfig: &peer.StaticCollectionConfig{ 585 Name: "col3", 586 }, 587 }, 588 }, 589 } 590 591 store2 := Dig2PvtRWSetWithConfig{ 592 privdatacommon.DigKey{ 593 TxId: "txID1", 594 Collection: "col3", 595 Namespace: "ns1", 596 }: p3TransientStore, 597 } 598 policyStore = newCollectionStore().withPolicy("col3", uint64(100)).thatMapsTo("p1") 599 factoryMock3 := &mocks.CollectionAccessFactory{} 600 accessPolicyMock3 := &mocks.CollectionAccessPolicy{} 601 Setup(accessPolicyMock3, 1, 2, func(data protoutil.SignedData) bool { 602 return bytes.Equal(data.Identity, []byte("p1")) 603 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 604 factoryMock3.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock3, nil) 605 606 p3 := gn.newPuller("p3", policyStore, factoryMock3) 607 dig2 := &proto.PvtDataDigest{ 608 TxId: "txID1", 609 Collection: "col3", 610 Namespace: "ns1", 611 } 612 613 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig2)), mock.Anything).Return(store2, true, nil) 614 615 dasf := &digestsAndSourceFactory{} 616 fetchedMessages, err := p1.fetch(dasf.mapDigest(toDigKey(dig1)).toSources().mapDigest(toDigKey(dig2)).toSources().create()) 617 assert.NoError(t, err) 618 rws1 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[0]) 619 rws2 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[1]) 620 rws3 := util.PrivateRWSet(fetchedMessages.AvailableElements[1].Payload[0]) 621 rws4 := util.PrivateRWSet(fetchedMessages.AvailableElements[1].Payload[1]) 622 fetched := []util.PrivateRWSet{rws1, rws2, rws3, rws4} 623 assert.Contains(t, fetched, p2TransientStore.RWSet[0]) 624 assert.Contains(t, fetched, p2TransientStore.RWSet[1]) 625 assert.Contains(t, fetched, p3TransientStore.RWSet[0]) 626 assert.Contains(t, fetched, p3TransientStore.RWSet[1]) 627 } 628 629 func TestPullerRetries(t *testing.T) { 630 t.Parallel() 631 // Scenario: p1 pulls from p2, p3, p4 and p5. 632 // Only p3 considers p1 to be eligible to receive the data. 633 // The rest consider p1 as not eligible. 634 gn := &gossipNetwork{} 635 factoryMock1 := &mocks.CollectionAccessFactory{} 636 accessPolicyMock1 := &mocks.CollectionAccessPolicy{} 637 Setup(accessPolicyMock1, 1, 2, func(data protoutil.SignedData) bool { 638 return bytes.Equal(data.Identity, []byte("p2")) || bytes.Equal(data.Identity, []byte("p3")) || 639 bytes.Equal(data.Identity, []byte("p4")) || 640 bytes.Equal(data.Identity, []byte("p5")) 641 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 642 factoryMock1.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock1, nil) 643 644 // p1 645 policyStore := newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2", "p3", "p4", "p5") 646 p1 := gn.newPuller("p1", policyStore, factoryMock1, membership(peerData{"p2", uint64(1)}, 647 peerData{"p3", uint64(1)}, peerData{"p4", uint64(1)}, peerData{"p5", uint64(1)})...) 648 649 // p2, p3, p4, and p5 have the same transient store 650 transientStore := &util.PrivateRWSetWithConfig{ 651 RWSet: newPRWSet(), 652 CollectionConfig: &peer.CollectionConfig{ 653 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 654 StaticCollectionConfig: &peer.StaticCollectionConfig{ 655 Name: "col1", 656 }, 657 }, 658 }, 659 } 660 661 dig := &proto.PvtDataDigest{ 662 TxId: "txID1", 663 Collection: "col1", 664 Namespace: "ns1", 665 } 666 667 store := Dig2PvtRWSetWithConfig{ 668 privdatacommon.DigKey{ 669 TxId: "txID1", 670 Collection: "col1", 671 Namespace: "ns1", 672 }: transientStore, 673 } 674 675 // p2 676 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2") 677 factoryMock2 := &mocks.CollectionAccessFactory{} 678 accessPolicyMock2 := &mocks.CollectionAccessPolicy{} 679 Setup(accessPolicyMock2, 1, 2, func(data protoutil.SignedData) bool { 680 return bytes.Equal(data.Identity, []byte("p2")) 681 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 682 factoryMock2.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock2, nil) 683 684 p2 := gn.newPuller("p2", policyStore, factoryMock2) 685 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), uint64(0)).Return(store, true, nil) 686 687 // p3 688 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p1") 689 factoryMock3 := &mocks.CollectionAccessFactory{} 690 accessPolicyMock3 := &mocks.CollectionAccessPolicy{} 691 Setup(accessPolicyMock3, 1, 2, func(data protoutil.SignedData) bool { 692 return bytes.Equal(data.Identity, []byte("p1")) 693 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 694 factoryMock3.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock3, nil) 695 696 p3 := gn.newPuller("p3", policyStore, factoryMock3) 697 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), uint64(0)).Return(store, true, nil) 698 699 // p4 700 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p4") 701 factoryMock4 := &mocks.CollectionAccessFactory{} 702 accessPolicyMock4 := &mocks.CollectionAccessPolicy{} 703 Setup(accessPolicyMock4, 1, 2, func(data protoutil.SignedData) bool { 704 return bytes.Equal(data.Identity, []byte("p4")) 705 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 706 factoryMock4.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock4, nil) 707 708 p4 := gn.newPuller("p4", policyStore, factoryMock4) 709 p4.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), uint64(0)).Return(store, true, nil) 710 711 // p5 712 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p5") 713 factoryMock5 := &mocks.CollectionAccessFactory{} 714 accessPolicyMock5 := &mocks.CollectionAccessPolicy{} 715 Setup(accessPolicyMock5, 1, 2, func(data protoutil.SignedData) bool { 716 return bytes.Equal(data.Identity, []byte("p5")) 717 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 718 factoryMock5.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock5, nil) 719 720 p5 := gn.newPuller("p5", policyStore, factoryMock5) 721 p5.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), uint64(0)).Return(store, true, nil) 722 723 // Fetch from someone 724 dasf := &digestsAndSourceFactory{} 725 fetchedMessages, err := p1.fetch(dasf.mapDigest(toDigKey(dig)).toSources().create()) 726 assert.NoError(t, err) 727 rws1 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[0]) 728 rws2 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[1]) 729 fetched := []util.PrivateRWSet{rws1, rws2} 730 assert.NoError(t, err) 731 assert.Equal(t, transientStore.RWSet, fetched) 732 } 733 734 func TestPullerPreferEndorsers(t *testing.T) { 735 t.Parallel() 736 // Scenario: p1 pulls from p2, p3, p4, p5 737 // and the only endorser for col1 is p3, so it should be selected 738 // at the top priority for col1. 739 // for col2, only p2 should have the data, but its not an endorser of the data. 740 gn := &gossipNetwork{} 741 factoryMock := &mocks.CollectionAccessFactory{} 742 accessPolicyMock := &mocks.CollectionAccessPolicy{} 743 Setup(accessPolicyMock, 1, 2, func(data protoutil.SignedData) bool { 744 return bytes.Equal(data.Identity, []byte("p2")) || bytes.Equal(data.Identity, []byte("p1")) 745 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 746 factoryMock.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock, nil) 747 748 policyStore := newCollectionStore(). 749 withPolicy("col1", uint64(100)). 750 thatMapsTo("p1", "p2", "p3", "p4", "p5"). 751 withPolicy("col2", uint64(100)). 752 thatMapsTo("p1", "p2") 753 p1 := gn.newPuller("p1", policyStore, factoryMock, membership(peerData{"p2", uint64(1)}, 754 peerData{"p3", uint64(1)}, peerData{"p4", uint64(1)}, peerData{"p5", uint64(1)})...) 755 756 p3TransientStore := &util.PrivateRWSetWithConfig{ 757 RWSet: newPRWSet(), 758 CollectionConfig: &peer.CollectionConfig{ 759 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 760 StaticCollectionConfig: &peer.StaticCollectionConfig{ 761 Name: "col2", 762 }, 763 }, 764 }, 765 } 766 767 p2TransientStore := &util.PrivateRWSetWithConfig{ 768 RWSet: newPRWSet(), 769 CollectionConfig: &peer.CollectionConfig{ 770 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 771 StaticCollectionConfig: &peer.StaticCollectionConfig{ 772 Name: "col2", 773 }, 774 }, 775 }, 776 } 777 778 p2 := gn.newPuller("p2", policyStore, factoryMock) 779 p3 := gn.newPuller("p3", policyStore, factoryMock) 780 gn.newPuller("p4", policyStore, factoryMock) 781 gn.newPuller("p5", policyStore, factoryMock) 782 783 dig1 := &proto.PvtDataDigest{ 784 TxId: "txID1", 785 Collection: "col1", 786 Namespace: "ns1", 787 } 788 789 dig2 := &proto.PvtDataDigest{ 790 TxId: "txID1", 791 Collection: "col2", 792 Namespace: "ns1", 793 } 794 795 store := Dig2PvtRWSetWithConfig{ 796 privdatacommon.DigKey{ 797 TxId: "txID1", 798 Collection: "col1", 799 Namespace: "ns1", 800 }: p3TransientStore, 801 privdatacommon.DigKey{ 802 TxId: "txID1", 803 Collection: "col2", 804 Namespace: "ns1", 805 }: p2TransientStore, 806 } 807 808 // We only define an action for dig2 on p2, and the test would fail with panic if any other peer is asked for 809 // a private RWSet on dig2 810 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig2)), uint64(0)).Return(store, true, nil) 811 812 // We only define an action for dig1 on p3, and the test would fail with panic if any other peer is asked for 813 // a private RWSet on dig1 814 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig1)), uint64(0)).Return(store, true, nil) 815 816 dasf := &digestsAndSourceFactory{} 817 d2s := dasf.mapDigest(toDigKey(dig1)).toSources("p3").mapDigest(toDigKey(dig2)).toSources().create() 818 fetchedMessages, err := p1.fetch(d2s) 819 assert.NoError(t, err) 820 rws1 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[0]) 821 rws2 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[1]) 822 rws3 := util.PrivateRWSet(fetchedMessages.AvailableElements[1].Payload[0]) 823 rws4 := util.PrivateRWSet(fetchedMessages.AvailableElements[1].Payload[1]) 824 fetched := []util.PrivateRWSet{rws1, rws2, rws3, rws4} 825 assert.Contains(t, fetched, p3TransientStore.RWSet[0]) 826 assert.Contains(t, fetched, p3TransientStore.RWSet[1]) 827 assert.Contains(t, fetched, p2TransientStore.RWSet[0]) 828 assert.Contains(t, fetched, p2TransientStore.RWSet[1]) 829 } 830 831 func TestPullerFetchReconciledItemsPreferPeersFromOriginalConfig(t *testing.T) { 832 t.Parallel() 833 // Scenario: p1 pulls from p2, p3, p4, p5 834 // the only peer that was in the collection config while data was created for col1 is p3, so it should be selected 835 // at the top priority for col1. 836 // for col2, p3 was in the collection config while the data was created but was removed from collection and now only p2 should have the data. 837 // so obviously p2 should be selected for col2. 838 gn := &gossipNetwork{} 839 factoryMock := &mocks.CollectionAccessFactory{} 840 accessPolicyMock := &mocks.CollectionAccessPolicy{} 841 Setup(accessPolicyMock, 1, 2, func(data protoutil.SignedData) bool { 842 return bytes.Equal(data.Identity, []byte("p2")) || bytes.Equal(data.Identity, []byte("p1")) 843 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 844 factoryMock.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock, nil) 845 846 policyStore := newCollectionStore(). 847 withPolicy("col1", uint64(100)). 848 thatMapsTo("p1", "p2", "p3", "p4", "p5"). 849 withPolicy("col2", uint64(100)). 850 thatMapsTo("p1", "p2"). 851 withAccessFilter(func(data protoutil.SignedData) bool { 852 return bytes.Equal(data.Identity, []byte("p3")) 853 }) 854 855 p1 := gn.newPuller("p1", policyStore, factoryMock, membership(peerData{"p2", uint64(1)}, 856 peerData{"p3", uint64(1)}, peerData{"p4", uint64(1)}, peerData{"p5", uint64(1)})...) 857 858 p3TransientStore := &util.PrivateRWSetWithConfig{ 859 RWSet: newPRWSet(), 860 CollectionConfig: &peer.CollectionConfig{ 861 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 862 StaticCollectionConfig: &peer.StaticCollectionConfig{ 863 Name: "col2", 864 }, 865 }, 866 }, 867 } 868 869 p2TransientStore := &util.PrivateRWSetWithConfig{ 870 RWSet: newPRWSet(), 871 CollectionConfig: &peer.CollectionConfig{ 872 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 873 StaticCollectionConfig: &peer.StaticCollectionConfig{ 874 Name: "col2", 875 }, 876 }, 877 }, 878 } 879 880 p2 := gn.newPuller("p2", policyStore, factoryMock) 881 p3 := gn.newPuller("p3", policyStore, factoryMock) 882 gn.newPuller("p4", policyStore, factoryMock) 883 gn.newPuller("p5", policyStore, factoryMock) 884 885 dig1 := &proto.PvtDataDigest{ 886 TxId: "txID1", 887 Collection: "col1", 888 Namespace: "ns1", 889 } 890 891 dig2 := &proto.PvtDataDigest{ 892 TxId: "txID1", 893 Collection: "col2", 894 Namespace: "ns1", 895 } 896 897 store := Dig2PvtRWSetWithConfig{ 898 privdatacommon.DigKey{ 899 TxId: "txID1", 900 Collection: "col1", 901 Namespace: "ns1", 902 }: p3TransientStore, 903 privdatacommon.DigKey{ 904 TxId: "txID1", 905 Collection: "col2", 906 Namespace: "ns1", 907 }: p2TransientStore, 908 } 909 910 // We only define an action for dig2 on p2, and the test would fail with panic if any other peer is asked for 911 // a private RWSet on dig2 912 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig2)), uint64(0)).Return(store, true, nil) 913 914 // We only define an action for dig1 on p3, and the test would fail with panic if any other peer is asked for 915 // a private RWSet on dig1 916 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig1)), uint64(0)).Return(store, true, nil) 917 918 d2cc := privdatacommon.Dig2CollectionConfig{ 919 privdatacommon.DigKey{ 920 TxId: "txID1", 921 Collection: "col1", 922 Namespace: "ns1", 923 }: &peer.StaticCollectionConfig{ 924 Name: "col1", 925 }, 926 privdatacommon.DigKey{ 927 TxId: "txID1", 928 Collection: "col2", 929 Namespace: "ns1", 930 }: &peer.StaticCollectionConfig{ 931 Name: "col2", 932 }, 933 } 934 935 fetchedMessages, err := p1.FetchReconciledItems(d2cc) 936 assert.NoError(t, err) 937 rws1 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[0]) 938 rws2 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[1]) 939 rws3 := util.PrivateRWSet(fetchedMessages.AvailableElements[1].Payload[0]) 940 rws4 := util.PrivateRWSet(fetchedMessages.AvailableElements[1].Payload[1]) 941 fetched := []util.PrivateRWSet{rws1, rws2, rws3, rws4} 942 assert.Contains(t, fetched, p3TransientStore.RWSet[0]) 943 assert.Contains(t, fetched, p3TransientStore.RWSet[1]) 944 assert.Contains(t, fetched, p2TransientStore.RWSet[0]) 945 assert.Contains(t, fetched, p2TransientStore.RWSet[1]) 946 } 947 948 func TestPullerAvoidPullingPurgedData(t *testing.T) { 949 // Scenario: p1 missing private data for col1 950 // p2 and p3 is suppose to have it, while p3 has more advanced 951 // ledger and based on BTL already purged data for, so p1 952 // suppose to fetch data only from p2 953 954 t.Parallel() 955 gn := &gossipNetwork{} 956 factoryMock := &mocks.CollectionAccessFactory{} 957 accessPolicyMock := &mocks.CollectionAccessPolicy{} 958 Setup(accessPolicyMock, 1, 2, func(data protoutil.SignedData) bool { 959 return bytes.Equal(data.Identity, []byte("p1")) 960 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 961 factoryMock.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock, nil) 962 963 policyStore := newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p1", "p2", "p3"). 964 withPolicy("col2", uint64(1000)).thatMapsTo("p1", "p2", "p3") 965 966 // p2 is at ledger height 1, while p2 is at 111 which is beyond BTL defined for col1 (100) 967 p1 := gn.newPuller("p1", policyStore, factoryMock, membership(peerData{"p2", uint64(1)}, 968 peerData{"p3", uint64(111)})...) 969 970 privateData1 := &util.PrivateRWSetWithConfig{ 971 RWSet: newPRWSet(), 972 CollectionConfig: &peer.CollectionConfig{ 973 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 974 StaticCollectionConfig: &peer.StaticCollectionConfig{ 975 Name: "col1", 976 }, 977 }, 978 }, 979 } 980 privateData2 := &util.PrivateRWSetWithConfig{ 981 RWSet: newPRWSet(), 982 CollectionConfig: &peer.CollectionConfig{ 983 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 984 StaticCollectionConfig: &peer.StaticCollectionConfig{ 985 Name: "col2", 986 }, 987 }, 988 }, 989 } 990 991 p2 := gn.newPuller("p2", policyStore, factoryMock) 992 p3 := gn.newPuller("p3", policyStore, factoryMock) 993 994 dig1 := &proto.PvtDataDigest{ 995 TxId: "txID1", 996 Collection: "col1", 997 Namespace: "ns1", 998 } 999 1000 dig2 := &proto.PvtDataDigest{ 1001 TxId: "txID1", 1002 Collection: "col2", 1003 Namespace: "ns1", 1004 } 1005 1006 store := Dig2PvtRWSetWithConfig{ 1007 privdatacommon.DigKey{ 1008 TxId: "txID1", 1009 Collection: "col1", 1010 Namespace: "ns1", 1011 }: privateData1, 1012 privdatacommon.DigKey{ 1013 TxId: "txID1", 1014 Collection: "col2", 1015 Namespace: "ns1", 1016 }: privateData2, 1017 } 1018 1019 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig1)), 0).Return(store, true, nil) 1020 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig1)), 0).Return(store, true, nil). 1021 Run( 1022 func(arg mock.Arguments) { 1023 assert.Fail(t, "we should not fetch private data from peers where it was purged") 1024 }, 1025 ) 1026 1027 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig2)), uint64(0)).Return(store, true, nil) 1028 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig2)), uint64(0)).Return(store, true, nil). 1029 Run( 1030 func(mock.Arguments) { 1031 assert.Fail(t, "we should not fetch private data of collection2 from peer 2") 1032 1033 }, 1034 ) 1035 1036 dasf := &digestsAndSourceFactory{} 1037 d2s := dasf.mapDigest(toDigKey(dig1)).toSources("p3", "p2").mapDigest(toDigKey(dig2)).toSources("p3").create() 1038 // trying to fetch missing pvt data for block seq 1 1039 fetchedMessages, err := p1.fetch(d2s) 1040 1041 assert.NoError(t, err) 1042 assert.Equal(t, 1, len(fetchedMessages.PurgedElements)) 1043 assert.Equal(t, dig1, fetchedMessages.PurgedElements[0]) 1044 p3.PrivateDataRetriever.(*dataRetrieverMock).AssertNumberOfCalls(t, "CollectionRWSet", 1) 1045 1046 } 1047 1048 type counterDataRetreiver struct { 1049 numberOfCalls int 1050 PrivateDataRetriever 1051 } 1052 1053 func (c *counterDataRetreiver) CollectionRWSet(dig []*proto.PvtDataDigest, blockNum uint64) (Dig2PvtRWSetWithConfig, bool, error) { 1054 c.numberOfCalls += 1 1055 return c.PrivateDataRetriever.CollectionRWSet(dig, blockNum) 1056 } 1057 1058 func (c *counterDataRetreiver) getNumberOfCalls() int { 1059 return c.numberOfCalls 1060 } 1061 1062 func TestPullerIntegratedWithDataRetreiver(t *testing.T) { 1063 t.Parallel() 1064 gn := &gossipNetwork{} 1065 1066 ns1, ns2 := "testChaincodeName1", "testChaincodeName2" 1067 col1, col2 := "testCollectionName1", "testCollectionName2" 1068 1069 ap := &mocks.CollectionAccessPolicy{} 1070 Setup(ap, 1, 2, func(data protoutil.SignedData) bool { 1071 return bytes.Equal(data.Identity, []byte("p1")) 1072 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 1073 1074 factoryMock := &mocks.CollectionAccessFactory{} 1075 factoryMock.On("AccessPolicy", mock.Anything, mock.Anything).Return(ap, nil) 1076 1077 policyStore := newCollectionStore().withPolicy(col1, uint64(1000)).thatMapsTo("p1", "p2"). 1078 withPolicy(col2, uint64(1000)).thatMapsTo("p1", "p2") 1079 1080 p1 := gn.newPuller("p1", policyStore, factoryMock, membership(peerData{"p2", uint64(10)})...) 1081 p2 := gn.newPuller("p2", policyStore, factoryMock, membership(peerData{"p1", uint64(1)})...) 1082 1083 committer := &mocks.Committer{} 1084 tempdir, err := ioutil.TempDir("", "ts") 1085 if err != nil { 1086 t.Fatalf("Failed to create test directory, got err %s", err) 1087 return 1088 } 1089 storeProvider, err := transientstore.NewStoreProvider(tempdir) 1090 if err != nil { 1091 t.Fatalf("Failed to open store, got err %s", err) 1092 return 1093 } 1094 store, err := storeProvider.OpenStore("test") 1095 if err != nil { 1096 t.Fatalf("Failed to open store, got err %s", err) 1097 return 1098 } 1099 defer storeProvider.Close() 1100 defer os.RemoveAll(tempdir) 1101 result := []*ledger.TxPvtData{ 1102 { 1103 WriteSet: &rwset.TxPvtReadWriteSet{ 1104 DataModel: rwset.TxReadWriteSet_KV, 1105 NsPvtRwset: []*rwset.NsPvtReadWriteSet{ 1106 pvtReadWriteSet(ns1, col1, []byte{1}), 1107 pvtReadWriteSet(ns1, col1, []byte{2}), 1108 }, 1109 }, 1110 SeqInBlock: 1, 1111 }, 1112 { 1113 WriteSet: &rwset.TxPvtReadWriteSet{ 1114 DataModel: rwset.TxReadWriteSet_KV, 1115 NsPvtRwset: []*rwset.NsPvtReadWriteSet{ 1116 pvtReadWriteSet(ns2, col2, []byte{3}), 1117 pvtReadWriteSet(ns2, col2, []byte{4}), 1118 }, 1119 }, 1120 SeqInBlock: 2, 1121 }, 1122 } 1123 1124 committer.On("LedgerHeight").Return(uint64(10), nil) 1125 committer.On("GetPvtDataByNum", uint64(5), mock.Anything).Return(result, nil) 1126 historyRetreiver := &mocks.ConfigHistoryRetriever{} 1127 historyRetreiver.On("MostRecentCollectionConfigBelow", mock.Anything, ns1).Return(newCollectionConfig(col1), nil) 1128 historyRetreiver.On("MostRecentCollectionConfigBelow", mock.Anything, ns2).Return(newCollectionConfig(col2), nil) 1129 committer.On("GetConfigHistoryRetriever").Return(historyRetreiver, nil) 1130 1131 dataRetreiver := &counterDataRetreiver{PrivateDataRetriever: NewDataRetriever(store, committer), numberOfCalls: 0} 1132 p2.PrivateDataRetriever = dataRetreiver 1133 1134 dig1 := &privdatacommon.DigKey{ 1135 TxId: "txID1", 1136 Collection: col1, 1137 Namespace: ns1, 1138 BlockSeq: 5, 1139 SeqInBlock: 1, 1140 } 1141 1142 dig2 := &privdatacommon.DigKey{ 1143 TxId: "txID1", 1144 Collection: col2, 1145 Namespace: ns2, 1146 BlockSeq: 5, 1147 SeqInBlock: 2, 1148 } 1149 1150 dasf := &digestsAndSourceFactory{} 1151 d2s := dasf.mapDigest(dig1).toSources("p2").mapDigest(dig2).toSources("p2").create() 1152 fetchedMessages, err := p1.fetch(d2s) 1153 assert.NoError(t, err) 1154 assert.Equal(t, 2, len(fetchedMessages.AvailableElements)) 1155 assert.Equal(t, 1, dataRetreiver.getNumberOfCalls()) 1156 assert.Equal(t, 2, len(fetchedMessages.AvailableElements[0].Payload)) 1157 assert.Equal(t, 2, len(fetchedMessages.AvailableElements[1].Payload)) 1158 } 1159 1160 func toDigKey(dig *proto.PvtDataDigest) *privdatacommon.DigKey { 1161 return &privdatacommon.DigKey{ 1162 TxId: dig.TxId, 1163 BlockSeq: dig.BlockSeq, 1164 SeqInBlock: dig.SeqInBlock, 1165 Namespace: dig.Namespace, 1166 Collection: dig.Collection, 1167 } 1168 } 1169 1170 func TestPullerMetrics(t *testing.T) { 1171 t.Parallel() 1172 // Scenario: p1 pulls from p2 and sends metric reports 1173 gn := &gossipNetwork{} 1174 policyStore := newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2") 1175 factoryMock1 := &mocks.CollectionAccessFactory{} 1176 policyMock1 := &mocks.CollectionAccessPolicy{} 1177 Setup(policyMock1, 1, 2, func(data protoutil.SignedData) bool { 1178 return bytes.Equal(data.Identity, []byte("p2")) 1179 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 1180 factoryMock1.On("AccessPolicy", mock.Anything, mock.Anything).Return(policyMock1, nil) 1181 1182 testMetricProvider := gmetricsmocks.TestUtilConstructMetricProvider() 1183 metrics := metrics.NewGossipMetrics(testMetricProvider.FakeProvider).PrivdataMetrics 1184 1185 p1 := gn.newPullerWithMetrics(metrics, "p1", policyStore, factoryMock1, membership(peerData{"p2", uint64(1)})...) 1186 1187 p2TransientStore := &util.PrivateRWSetWithConfig{ 1188 RWSet: newPRWSet(), 1189 CollectionConfig: &peer.CollectionConfig{ 1190 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 1191 StaticCollectionConfig: &peer.StaticCollectionConfig{ 1192 Name: "col1", 1193 }, 1194 }, 1195 }, 1196 } 1197 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p1") 1198 factoryMock2 := &mocks.CollectionAccessFactory{} 1199 policyMock2 := &mocks.CollectionAccessPolicy{} 1200 Setup(policyMock2, 1, 2, func(data protoutil.SignedData) bool { 1201 return bytes.Equal(data.Identity, []byte("p1")) 1202 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 1203 factoryMock2.On("AccessPolicy", mock.Anything, mock.Anything).Return(policyMock2, nil) 1204 1205 p2 := gn.newPullerWithMetrics(metrics, "p2", policyStore, factoryMock2) 1206 1207 dig := &proto.PvtDataDigest{ 1208 TxId: "txID1", 1209 Collection: "col1", 1210 Namespace: "ns1", 1211 } 1212 1213 store := Dig2PvtRWSetWithConfig{ 1214 privdatacommon.DigKey{ 1215 TxId: "txID1", 1216 Collection: "col1", 1217 Namespace: "ns1", 1218 }: p2TransientStore, 1219 } 1220 1221 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), 1222 uint64(0)).Return(store, true, nil) 1223 1224 dasf := &digestsAndSourceFactory{} 1225 1226 fetchedMessages, err := p1.fetch(dasf.mapDigest(toDigKey(dig)).toSources().create()) 1227 rws1 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[0]) 1228 rws2 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[1]) 1229 fetched := []util.PrivateRWSet{rws1, rws2} 1230 assert.NoError(t, err) 1231 assert.Equal(t, p2TransientStore.RWSet, fetched) 1232 1233 assert.Equal(t, 1234 []string{"channel", "A"}, 1235 testMetricProvider.FakePullDuration.WithArgsForCall(0), 1236 ) 1237 assert.True(t, testMetricProvider.FakePullDuration.ObserveArgsForCall(0) > 0) 1238 assert.Equal(t, 1239 []string{"channel", "A"}, 1240 testMetricProvider.FakeRetrieveDuration.WithArgsForCall(0), 1241 ) 1242 assert.True(t, testMetricProvider.FakeRetrieveDuration.ObserveArgsForCall(0) > 0) 1243 }