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