github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/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/osdi23p228/fabric/common/metrics/disabled" 22 "github.com/osdi23p228/fabric/core/common/privdata" 23 "github.com/osdi23p228/fabric/core/ledger" 24 "github.com/osdi23p228/fabric/core/transientstore" 25 "github.com/osdi23p228/fabric/gossip/api" 26 "github.com/osdi23p228/fabric/gossip/comm" 27 "github.com/osdi23p228/fabric/gossip/common" 28 "github.com/osdi23p228/fabric/gossip/discovery" 29 "github.com/osdi23p228/fabric/gossip/filter" 30 "github.com/osdi23p228/fabric/gossip/metrics" 31 gmetricsmocks "github.com/osdi23p228/fabric/gossip/metrics/mocks" 32 privdatacommon "github.com/osdi23p228/fabric/gossip/privdata/common" 33 "github.com/osdi23p228/fabric/gossip/privdata/mocks" 34 "github.com/osdi23p228/fabric/gossip/protoext" 35 "github.com/osdi23p228/fabric/gossip/util" 36 "github.com/osdi23p228/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 // Scenario: p1 pulls from p2 and not from p3 315 // and succeeds - p1 asks from p2 (and not from p3!) for the 316 // expected digest 317 gn := &gossipNetwork{} 318 policyStore := newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2") 319 factoryMock1 := &mocks.CollectionAccessFactory{} 320 policyMock1 := &mocks.CollectionAccessPolicy{} 321 Setup(policyMock1, 1, 2, func(data protoutil.SignedData) bool { 322 return bytes.Equal(data.Identity, []byte("p2")) 323 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 324 factoryMock1.On("AccessPolicy", mock.Anything, mock.Anything).Return(policyMock1, nil) 325 p1 := gn.newPuller("p1", policyStore, factoryMock1, membership(peerData{"p2", uint64(1)}, peerData{"p3", uint64(1)})...) 326 327 p2TransientStore := &util.PrivateRWSetWithConfig{ 328 RWSet: newPRWSet(), 329 CollectionConfig: &peer.CollectionConfig{ 330 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 331 StaticCollectionConfig: &peer.StaticCollectionConfig{ 332 Name: "col1", 333 }, 334 }, 335 }, 336 } 337 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p1") 338 factoryMock2 := &mocks.CollectionAccessFactory{} 339 policyMock2 := &mocks.CollectionAccessPolicy{} 340 Setup(policyMock2, 1, 2, func(data protoutil.SignedData) bool { 341 return bytes.Equal(data.Identity, []byte("p1")) 342 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 343 factoryMock2.On("AccessPolicy", mock.Anything, mock.Anything).Return(policyMock2, nil) 344 345 p2 := gn.newPuller("p2", policyStore, factoryMock2) 346 dig := &proto.PvtDataDigest{ 347 TxId: "txID1", 348 Collection: "col1", 349 Namespace: "ns1", 350 } 351 352 store := Dig2PvtRWSetWithConfig{ 353 privdatacommon.DigKey{ 354 TxId: "txID1", 355 Collection: "col1", 356 Namespace: "ns1", 357 }: p2TransientStore, 358 } 359 360 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), uint64(0)).Return(store, true, nil) 361 362 factoryMock3 := &mocks.CollectionAccessFactory{} 363 policyMock3 := &mocks.CollectionAccessPolicy{} 364 Setup(policyMock3, 1, 2, func(data protoutil.SignedData) bool { 365 return false 366 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 367 factoryMock3.On("AccessPolicy", mock.Anything, mock.Anything).Return(policyMock3, nil) 368 369 p3 := gn.newPuller("p3", newCollectionStore(), factoryMock3) 370 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), uint64(0)).Run(func(_ mock.Arguments) { 371 t.Fatal("p3 shouldn't have been selected for pull") 372 }) 373 374 dasf := &digestsAndSourceFactory{} 375 376 fetchedMessages, err := p1.fetch(dasf.mapDigest(toDigKey(dig)).toSources().create()) 377 rws1 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[0]) 378 rws2 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[1]) 379 fetched := []util.PrivateRWSet{rws1, rws2} 380 assert.NoError(t, err) 381 assert.Equal(t, p2TransientStore.RWSet, fetched) 382 } 383 384 func TestPullerDataNotAvailable(t *testing.T) { 385 // Scenario: p1 pulls from p2 and not from p3 386 // but the data in p2 doesn't exist 387 gn := &gossipNetwork{} 388 policyStore := newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2") 389 factoryMock := &mocks.CollectionAccessFactory{} 390 factoryMock.On("AccessPolicy", mock.Anything, mock.Anything).Return(&mocks.CollectionAccessPolicy{}, nil) 391 392 p1 := gn.newPuller("p1", policyStore, factoryMock, membership(peerData{"p2", uint64(1)}, peerData{"p3", uint64(1)})...) 393 394 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p1") 395 p2 := gn.newPuller("p2", policyStore, factoryMock) 396 dig := &proto.PvtDataDigest{ 397 TxId: "txID1", 398 Collection: "col1", 399 Namespace: "ns1", 400 } 401 402 store := Dig2PvtRWSetWithConfig{ 403 privdatacommon.DigKey{ 404 TxId: "txID1", 405 Collection: "col1", 406 Namespace: "ns1", 407 }: &util.PrivateRWSetWithConfig{ 408 RWSet: []util.PrivateRWSet{}, 409 }, 410 } 411 412 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), mock.Anything).Return(store, true, nil) 413 414 p3 := gn.newPuller("p3", newCollectionStore(), factoryMock) 415 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), mock.Anything).Run(func(_ mock.Arguments) { 416 t.Fatal("p3 shouldn't have been selected for pull") 417 }) 418 419 dasf := &digestsAndSourceFactory{} 420 fetchedMessages, err := p1.fetch(dasf.mapDigest(toDigKey(dig)).toSources().create()) 421 assert.Empty(t, fetchedMessages.AvailableElements) 422 assert.NoError(t, err) 423 } 424 425 func TestPullerNoPeersKnown(t *testing.T) { 426 // Scenario: p1 doesn't know any peer and therefore fails fetching 427 gn := &gossipNetwork{} 428 policyStore := newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2", "p3") 429 factoryMock := &mocks.CollectionAccessFactory{} 430 factoryMock.On("AccessPolicy", mock.Anything, mock.Anything).Return(&mocks.CollectionAccessPolicy{}, nil) 431 432 p1 := gn.newPuller("p1", policyStore, factoryMock) 433 dasf := &digestsAndSourceFactory{} 434 d2s := dasf.mapDigest(&privdatacommon.DigKey{Collection: "col1", TxId: "txID1", Namespace: "ns1"}).toSources().create() 435 fetchedMessages, err := p1.fetch(d2s) 436 assert.Empty(t, fetchedMessages) 437 assert.Error(t, err) 438 assert.Contains(t, err.Error(), "Empty membership") 439 } 440 441 func TestPullPeerFilterError(t *testing.T) { 442 // Scenario: p1 attempts to fetch for the wrong channel 443 gn := &gossipNetwork{} 444 policyStore := newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2") 445 factoryMock := &mocks.CollectionAccessFactory{} 446 factoryMock.On("AccessPolicy", mock.Anything, mock.Anything).Return(&mocks.CollectionAccessPolicy{}, nil) 447 448 p1 := gn.newPuller("p1", policyStore, factoryMock) 449 gn.peers[0].On("PeerFilter", mock.Anything, mock.Anything).Return(nil, errors.New("Failed obtaining filter")) 450 dasf := &digestsAndSourceFactory{} 451 d2s := dasf.mapDigest(&privdatacommon.DigKey{Collection: "col1", TxId: "txID1", Namespace: "ns1"}).toSources().create() 452 fetchedMessages, err := p1.fetch(d2s) 453 assert.Error(t, err) 454 assert.Contains(t, err.Error(), "Failed obtaining filter") 455 assert.Empty(t, fetchedMessages) 456 } 457 458 func TestPullerPeerNotEligible(t *testing.T) { 459 // Scenario: p1 pulls from p2 or from p3 460 // but it's not eligible for pulling data from p2 or from p3 461 gn := &gossipNetwork{} 462 policyStore := newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2", "p3") 463 factoryMock1 := &mocks.CollectionAccessFactory{} 464 accessPolicyMock1 := &mocks.CollectionAccessPolicy{} 465 Setup(accessPolicyMock1, 1, 2, func(data protoutil.SignedData) bool { 466 return bytes.Equal(data.Identity, []byte("p2")) || bytes.Equal(data.Identity, []byte("p3")) 467 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 468 factoryMock1.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock1, nil) 469 470 p1 := gn.newPuller("p1", policyStore, factoryMock1, membership(peerData{"p2", uint64(1)}, peerData{"p3", uint64(1)})...) 471 472 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2") 473 factoryMock2 := &mocks.CollectionAccessFactory{} 474 accessPolicyMock2 := &mocks.CollectionAccessPolicy{} 475 Setup(accessPolicyMock2, 1, 2, func(data protoutil.SignedData) bool { 476 return bytes.Equal(data.Identity, []byte("p2")) 477 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 478 factoryMock2.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock2, nil) 479 480 p2 := gn.newPuller("p2", policyStore, factoryMock2) 481 482 dig := &proto.PvtDataDigest{ 483 TxId: "txID1", 484 Collection: "col1", 485 Namespace: "ns1", 486 } 487 488 store := Dig2PvtRWSetWithConfig{ 489 privdatacommon.DigKey{ 490 TxId: "txID1", 491 Collection: "col1", 492 Namespace: "ns1", 493 }: &util.PrivateRWSetWithConfig{ 494 RWSet: newPRWSet(), 495 CollectionConfig: &peer.CollectionConfig{ 496 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 497 StaticCollectionConfig: &peer.StaticCollectionConfig{ 498 Name: "col1", 499 }, 500 }, 501 }, 502 }, 503 } 504 505 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), mock.Anything).Return(store, true, nil) 506 507 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p3") 508 factoryMock3 := &mocks.CollectionAccessFactory{} 509 accessPolicyMock3 := &mocks.CollectionAccessPolicy{} 510 Setup(accessPolicyMock3, 1, 2, func(data protoutil.SignedData) bool { 511 return bytes.Equal(data.Identity, []byte("p3")) 512 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 513 factoryMock3.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock1, nil) 514 515 p3 := gn.newPuller("p3", policyStore, factoryMock3) 516 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), mock.Anything).Return(store, true, nil) 517 dasf := &digestsAndSourceFactory{} 518 d2s := dasf.mapDigest(&privdatacommon.DigKey{Collection: "col1", TxId: "txID1", Namespace: "ns1"}).toSources().create() 519 fetchedMessages, err := p1.fetch(d2s) 520 assert.Empty(t, fetchedMessages.AvailableElements) 521 assert.NoError(t, err) 522 } 523 524 func TestPullerDifferentPeersDifferentCollections(t *testing.T) { 525 // Scenario: p1 pulls from p2 and from p3 526 // and each has different collections 527 gn := &gossipNetwork{} 528 factoryMock1 := &mocks.CollectionAccessFactory{} 529 accessPolicyMock1 := &mocks.CollectionAccessPolicy{} 530 Setup(accessPolicyMock1, 1, 2, func(data protoutil.SignedData) bool { 531 return bytes.Equal(data.Identity, []byte("p2")) || bytes.Equal(data.Identity, []byte("p3")) 532 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 533 factoryMock1.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock1, nil) 534 535 policyStore := newCollectionStore().withPolicy("col2", uint64(100)).thatMapsTo("p2").withPolicy("col3", uint64(100)).thatMapsTo("p3") 536 p1 := gn.newPuller("p1", policyStore, factoryMock1, membership(peerData{"p2", uint64(1)}, peerData{"p3", uint64(1)})...) 537 538 p2TransientStore := &util.PrivateRWSetWithConfig{ 539 RWSet: newPRWSet(), 540 CollectionConfig: &peer.CollectionConfig{ 541 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 542 StaticCollectionConfig: &peer.StaticCollectionConfig{ 543 Name: "col2", 544 }, 545 }, 546 }, 547 } 548 549 policyStore = newCollectionStore().withPolicy("col2", uint64(100)).thatMapsTo("p1") 550 factoryMock2 := &mocks.CollectionAccessFactory{} 551 accessPolicyMock2 := &mocks.CollectionAccessPolicy{} 552 Setup(accessPolicyMock2, 1, 2, func(data protoutil.SignedData) bool { 553 return bytes.Equal(data.Identity, []byte("p1")) 554 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 555 factoryMock2.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock2, nil) 556 557 p2 := gn.newPuller("p2", policyStore, factoryMock2) 558 dig1 := &proto.PvtDataDigest{ 559 TxId: "txID1", 560 Collection: "col2", 561 Namespace: "ns1", 562 } 563 564 store1 := Dig2PvtRWSetWithConfig{ 565 privdatacommon.DigKey{ 566 TxId: "txID1", 567 Collection: "col2", 568 Namespace: "ns1", 569 }: p2TransientStore, 570 } 571 572 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig1)), mock.Anything).Return(store1, true, nil) 573 574 p3TransientStore := &util.PrivateRWSetWithConfig{ 575 RWSet: newPRWSet(), 576 CollectionConfig: &peer.CollectionConfig{ 577 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 578 StaticCollectionConfig: &peer.StaticCollectionConfig{ 579 Name: "col3", 580 }, 581 }, 582 }, 583 } 584 585 store2 := Dig2PvtRWSetWithConfig{ 586 privdatacommon.DigKey{ 587 TxId: "txID1", 588 Collection: "col3", 589 Namespace: "ns1", 590 }: p3TransientStore, 591 } 592 policyStore = newCollectionStore().withPolicy("col3", uint64(100)).thatMapsTo("p1") 593 factoryMock3 := &mocks.CollectionAccessFactory{} 594 accessPolicyMock3 := &mocks.CollectionAccessPolicy{} 595 Setup(accessPolicyMock3, 1, 2, func(data protoutil.SignedData) bool { 596 return bytes.Equal(data.Identity, []byte("p1")) 597 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 598 factoryMock3.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock3, nil) 599 600 p3 := gn.newPuller("p3", policyStore, factoryMock3) 601 dig2 := &proto.PvtDataDigest{ 602 TxId: "txID1", 603 Collection: "col3", 604 Namespace: "ns1", 605 } 606 607 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig2)), mock.Anything).Return(store2, true, nil) 608 609 dasf := &digestsAndSourceFactory{} 610 fetchedMessages, err := p1.fetch(dasf.mapDigest(toDigKey(dig1)).toSources().mapDigest(toDigKey(dig2)).toSources().create()) 611 assert.NoError(t, err) 612 rws1 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[0]) 613 rws2 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[1]) 614 rws3 := util.PrivateRWSet(fetchedMessages.AvailableElements[1].Payload[0]) 615 rws4 := util.PrivateRWSet(fetchedMessages.AvailableElements[1].Payload[1]) 616 fetched := []util.PrivateRWSet{rws1, rws2, rws3, rws4} 617 assert.Contains(t, fetched, p2TransientStore.RWSet[0]) 618 assert.Contains(t, fetched, p2TransientStore.RWSet[1]) 619 assert.Contains(t, fetched, p3TransientStore.RWSet[0]) 620 assert.Contains(t, fetched, p3TransientStore.RWSet[1]) 621 } 622 623 func TestPullerRetries(t *testing.T) { 624 // Scenario: p1 pulls from p2, p3, p4 and p5. 625 // Only p3 considers p1 to be eligible to receive the data. 626 // The rest consider p1 as not eligible. 627 gn := &gossipNetwork{} 628 factoryMock1 := &mocks.CollectionAccessFactory{} 629 accessPolicyMock1 := &mocks.CollectionAccessPolicy{} 630 Setup(accessPolicyMock1, 1, 2, func(data protoutil.SignedData) bool { 631 return bytes.Equal(data.Identity, []byte("p2")) || bytes.Equal(data.Identity, []byte("p3")) || 632 bytes.Equal(data.Identity, []byte("p4")) || 633 bytes.Equal(data.Identity, []byte("p5")) 634 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 635 factoryMock1.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock1, nil) 636 637 // p1 638 policyStore := newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2", "p3", "p4", "p5") 639 p1 := gn.newPuller("p1", policyStore, factoryMock1, membership(peerData{"p2", uint64(1)}, 640 peerData{"p3", uint64(1)}, peerData{"p4", uint64(1)}, peerData{"p5", uint64(1)})...) 641 642 // p2, p3, p4, and p5 have the same transient store 643 transientStore := &util.PrivateRWSetWithConfig{ 644 RWSet: newPRWSet(), 645 CollectionConfig: &peer.CollectionConfig{ 646 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 647 StaticCollectionConfig: &peer.StaticCollectionConfig{ 648 Name: "col1", 649 }, 650 }, 651 }, 652 } 653 654 dig := &proto.PvtDataDigest{ 655 TxId: "txID1", 656 Collection: "col1", 657 Namespace: "ns1", 658 } 659 660 store := Dig2PvtRWSetWithConfig{ 661 privdatacommon.DigKey{ 662 TxId: "txID1", 663 Collection: "col1", 664 Namespace: "ns1", 665 }: transientStore, 666 } 667 668 // p2 669 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2") 670 factoryMock2 := &mocks.CollectionAccessFactory{} 671 accessPolicyMock2 := &mocks.CollectionAccessPolicy{} 672 Setup(accessPolicyMock2, 1, 2, func(data protoutil.SignedData) bool { 673 return bytes.Equal(data.Identity, []byte("p2")) 674 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 675 factoryMock2.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock2, nil) 676 677 p2 := gn.newPuller("p2", policyStore, factoryMock2) 678 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), uint64(0)).Return(store, true, nil) 679 680 // p3 681 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p1") 682 factoryMock3 := &mocks.CollectionAccessFactory{} 683 accessPolicyMock3 := &mocks.CollectionAccessPolicy{} 684 Setup(accessPolicyMock3, 1, 2, func(data protoutil.SignedData) bool { 685 return bytes.Equal(data.Identity, []byte("p1")) 686 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 687 factoryMock3.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock3, nil) 688 689 p3 := gn.newPuller("p3", policyStore, factoryMock3) 690 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), uint64(0)).Return(store, true, nil) 691 692 // p4 693 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p4") 694 factoryMock4 := &mocks.CollectionAccessFactory{} 695 accessPolicyMock4 := &mocks.CollectionAccessPolicy{} 696 Setup(accessPolicyMock4, 1, 2, func(data protoutil.SignedData) bool { 697 return bytes.Equal(data.Identity, []byte("p4")) 698 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 699 factoryMock4.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock4, nil) 700 701 p4 := gn.newPuller("p4", policyStore, factoryMock4) 702 p4.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), uint64(0)).Return(store, true, nil) 703 704 // p5 705 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p5") 706 factoryMock5 := &mocks.CollectionAccessFactory{} 707 accessPolicyMock5 := &mocks.CollectionAccessPolicy{} 708 Setup(accessPolicyMock5, 1, 2, func(data protoutil.SignedData) bool { 709 return bytes.Equal(data.Identity, []byte("p5")) 710 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 711 factoryMock5.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock5, nil) 712 713 p5 := gn.newPuller("p5", policyStore, factoryMock5) 714 p5.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), uint64(0)).Return(store, true, nil) 715 716 // Fetch from someone 717 dasf := &digestsAndSourceFactory{} 718 fetchedMessages, err := p1.fetch(dasf.mapDigest(toDigKey(dig)).toSources().create()) 719 assert.NoError(t, err) 720 rws1 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[0]) 721 rws2 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[1]) 722 fetched := []util.PrivateRWSet{rws1, rws2} 723 assert.NoError(t, err) 724 assert.Equal(t, transientStore.RWSet, fetched) 725 } 726 727 func TestPullerPreferEndorsers(t *testing.T) { 728 // Scenario: p1 pulls from p2, p3, p4, p5 729 // and the only endorser for col1 is p3, so it should be selected 730 // at the top priority for col1. 731 // for col2, only p2 should have the data, but its not an endorser of the data. 732 gn := &gossipNetwork{} 733 factoryMock := &mocks.CollectionAccessFactory{} 734 accessPolicyMock := &mocks.CollectionAccessPolicy{} 735 Setup(accessPolicyMock, 1, 2, func(data protoutil.SignedData) bool { 736 return bytes.Equal(data.Identity, []byte("p2")) || bytes.Equal(data.Identity, []byte("p1")) 737 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 738 factoryMock.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock, nil) 739 740 policyStore := newCollectionStore(). 741 withPolicy("col1", uint64(100)). 742 thatMapsTo("p1", "p2", "p3", "p4", "p5"). 743 withPolicy("col2", uint64(100)). 744 thatMapsTo("p1", "p2") 745 p1 := gn.newPuller("p1", policyStore, factoryMock, membership(peerData{"p2", uint64(1)}, 746 peerData{"p3", uint64(1)}, peerData{"p4", uint64(1)}, peerData{"p5", uint64(1)})...) 747 748 p3TransientStore := &util.PrivateRWSetWithConfig{ 749 RWSet: newPRWSet(), 750 CollectionConfig: &peer.CollectionConfig{ 751 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 752 StaticCollectionConfig: &peer.StaticCollectionConfig{ 753 Name: "col2", 754 }, 755 }, 756 }, 757 } 758 759 p2TransientStore := &util.PrivateRWSetWithConfig{ 760 RWSet: newPRWSet(), 761 CollectionConfig: &peer.CollectionConfig{ 762 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 763 StaticCollectionConfig: &peer.StaticCollectionConfig{ 764 Name: "col2", 765 }, 766 }, 767 }, 768 } 769 770 p2 := gn.newPuller("p2", policyStore, factoryMock) 771 p3 := gn.newPuller("p3", policyStore, factoryMock) 772 gn.newPuller("p4", policyStore, factoryMock) 773 gn.newPuller("p5", policyStore, factoryMock) 774 775 dig1 := &proto.PvtDataDigest{ 776 TxId: "txID1", 777 Collection: "col1", 778 Namespace: "ns1", 779 } 780 781 dig2 := &proto.PvtDataDigest{ 782 TxId: "txID1", 783 Collection: "col2", 784 Namespace: "ns1", 785 } 786 787 store := Dig2PvtRWSetWithConfig{ 788 privdatacommon.DigKey{ 789 TxId: "txID1", 790 Collection: "col1", 791 Namespace: "ns1", 792 }: p3TransientStore, 793 privdatacommon.DigKey{ 794 TxId: "txID1", 795 Collection: "col2", 796 Namespace: "ns1", 797 }: p2TransientStore, 798 } 799 800 // We only define an action for dig2 on p2, and the test would fail with panic if any other peer is asked for 801 // a private RWSet on dig2 802 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig2)), uint64(0)).Return(store, true, nil) 803 804 // We only define an action for dig1 on p3, and the test would fail with panic if any other peer is asked for 805 // a private RWSet on dig1 806 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig1)), uint64(0)).Return(store, true, nil) 807 808 dasf := &digestsAndSourceFactory{} 809 d2s := dasf.mapDigest(toDigKey(dig1)).toSources("p3").mapDigest(toDigKey(dig2)).toSources().create() 810 fetchedMessages, err := p1.fetch(d2s) 811 assert.NoError(t, err) 812 rws1 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[0]) 813 rws2 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[1]) 814 rws3 := util.PrivateRWSet(fetchedMessages.AvailableElements[1].Payload[0]) 815 rws4 := util.PrivateRWSet(fetchedMessages.AvailableElements[1].Payload[1]) 816 fetched := []util.PrivateRWSet{rws1, rws2, rws3, rws4} 817 assert.Contains(t, fetched, p3TransientStore.RWSet[0]) 818 assert.Contains(t, fetched, p3TransientStore.RWSet[1]) 819 assert.Contains(t, fetched, p2TransientStore.RWSet[0]) 820 assert.Contains(t, fetched, p2TransientStore.RWSet[1]) 821 } 822 823 func TestPullerFetchReconciledItemsPreferPeersFromOriginalConfig(t *testing.T) { 824 // Scenario: p1 pulls from p2, p3, p4, p5 825 // the only peer that was in the collection config while data was created for col1 is p3, so it should be selected 826 // at the top priority for col1. 827 // 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. 828 // so obviously p2 should be selected for col2. 829 gn := &gossipNetwork{} 830 factoryMock := &mocks.CollectionAccessFactory{} 831 accessPolicyMock := &mocks.CollectionAccessPolicy{} 832 Setup(accessPolicyMock, 1, 2, func(data protoutil.SignedData) bool { 833 return bytes.Equal(data.Identity, []byte("p2")) || bytes.Equal(data.Identity, []byte("p1")) 834 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 835 factoryMock.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock, nil) 836 837 policyStore := newCollectionStore(). 838 withPolicy("col1", uint64(100)). 839 thatMapsTo("p1", "p2", "p3", "p4", "p5"). 840 withPolicy("col2", uint64(100)). 841 thatMapsTo("p1", "p2"). 842 withAccessFilter(func(data protoutil.SignedData) bool { 843 return bytes.Equal(data.Identity, []byte("p3")) 844 }) 845 846 p1 := gn.newPuller("p1", policyStore, factoryMock, membership(peerData{"p2", uint64(1)}, 847 peerData{"p3", uint64(1)}, peerData{"p4", uint64(1)}, peerData{"p5", uint64(1)})...) 848 849 p3TransientStore := &util.PrivateRWSetWithConfig{ 850 RWSet: newPRWSet(), 851 CollectionConfig: &peer.CollectionConfig{ 852 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 853 StaticCollectionConfig: &peer.StaticCollectionConfig{ 854 Name: "col2", 855 }, 856 }, 857 }, 858 } 859 860 p2TransientStore := &util.PrivateRWSetWithConfig{ 861 RWSet: newPRWSet(), 862 CollectionConfig: &peer.CollectionConfig{ 863 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 864 StaticCollectionConfig: &peer.StaticCollectionConfig{ 865 Name: "col2", 866 }, 867 }, 868 }, 869 } 870 871 p2 := gn.newPuller("p2", policyStore, factoryMock) 872 p3 := gn.newPuller("p3", policyStore, factoryMock) 873 gn.newPuller("p4", policyStore, factoryMock) 874 gn.newPuller("p5", policyStore, factoryMock) 875 876 dig1 := &proto.PvtDataDigest{ 877 TxId: "txID1", 878 Collection: "col1", 879 Namespace: "ns1", 880 } 881 882 dig2 := &proto.PvtDataDigest{ 883 TxId: "txID1", 884 Collection: "col2", 885 Namespace: "ns1", 886 } 887 888 store := Dig2PvtRWSetWithConfig{ 889 privdatacommon.DigKey{ 890 TxId: "txID1", 891 Collection: "col1", 892 Namespace: "ns1", 893 }: p3TransientStore, 894 privdatacommon.DigKey{ 895 TxId: "txID1", 896 Collection: "col2", 897 Namespace: "ns1", 898 }: p2TransientStore, 899 } 900 901 // We only define an action for dig2 on p2, and the test would fail with panic if any other peer is asked for 902 // a private RWSet on dig2 903 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig2)), uint64(0)).Return(store, true, nil) 904 905 // We only define an action for dig1 on p3, and the test would fail with panic if any other peer is asked for 906 // a private RWSet on dig1 907 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig1)), uint64(0)).Return(store, true, nil) 908 909 d2cc := privdatacommon.Dig2CollectionConfig{ 910 privdatacommon.DigKey{ 911 TxId: "txID1", 912 Collection: "col1", 913 Namespace: "ns1", 914 }: &peer.StaticCollectionConfig{ 915 Name: "col1", 916 }, 917 privdatacommon.DigKey{ 918 TxId: "txID1", 919 Collection: "col2", 920 Namespace: "ns1", 921 }: &peer.StaticCollectionConfig{ 922 Name: "col2", 923 }, 924 } 925 926 fetchedMessages, err := p1.FetchReconciledItems(d2cc) 927 assert.NoError(t, err) 928 rws1 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[0]) 929 rws2 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[1]) 930 rws3 := util.PrivateRWSet(fetchedMessages.AvailableElements[1].Payload[0]) 931 rws4 := util.PrivateRWSet(fetchedMessages.AvailableElements[1].Payload[1]) 932 fetched := []util.PrivateRWSet{rws1, rws2, rws3, rws4} 933 assert.Contains(t, fetched, p3TransientStore.RWSet[0]) 934 assert.Contains(t, fetched, p3TransientStore.RWSet[1]) 935 assert.Contains(t, fetched, p2TransientStore.RWSet[0]) 936 assert.Contains(t, fetched, p2TransientStore.RWSet[1]) 937 } 938 939 func TestPullerAvoidPullingPurgedData(t *testing.T) { 940 // Scenario: p1 missing private data for col1 941 // p2 and p3 is suppose to have it, while p3 has more advanced 942 // ledger and based on BTL already purged data for, so p1 943 // suppose to fetch data only from p2 944 gn := &gossipNetwork{} 945 factoryMock := &mocks.CollectionAccessFactory{} 946 accessPolicyMock := &mocks.CollectionAccessPolicy{} 947 Setup(accessPolicyMock, 1, 2, func(data protoutil.SignedData) bool { 948 return bytes.Equal(data.Identity, []byte("p1")) 949 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 950 factoryMock.On("AccessPolicy", mock.Anything, mock.Anything).Return(accessPolicyMock, nil) 951 952 policyStore := newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p1", "p2", "p3"). 953 withPolicy("col2", uint64(1000)).thatMapsTo("p1", "p2", "p3") 954 955 // p2 is at ledger height 1, while p2 is at 111 which is beyond BTL defined for col1 (100) 956 p1 := gn.newPuller("p1", policyStore, factoryMock, membership(peerData{"p2", uint64(1)}, 957 peerData{"p3", uint64(111)})...) 958 959 privateData1 := &util.PrivateRWSetWithConfig{ 960 RWSet: newPRWSet(), 961 CollectionConfig: &peer.CollectionConfig{ 962 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 963 StaticCollectionConfig: &peer.StaticCollectionConfig{ 964 Name: "col1", 965 }, 966 }, 967 }, 968 } 969 privateData2 := &util.PrivateRWSetWithConfig{ 970 RWSet: newPRWSet(), 971 CollectionConfig: &peer.CollectionConfig{ 972 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 973 StaticCollectionConfig: &peer.StaticCollectionConfig{ 974 Name: "col2", 975 }, 976 }, 977 }, 978 } 979 980 p2 := gn.newPuller("p2", policyStore, factoryMock) 981 p3 := gn.newPuller("p3", policyStore, factoryMock) 982 983 dig1 := &proto.PvtDataDigest{ 984 TxId: "txID1", 985 Collection: "col1", 986 Namespace: "ns1", 987 } 988 989 dig2 := &proto.PvtDataDigest{ 990 TxId: "txID1", 991 Collection: "col2", 992 Namespace: "ns1", 993 } 994 995 store := Dig2PvtRWSetWithConfig{ 996 privdatacommon.DigKey{ 997 TxId: "txID1", 998 Collection: "col1", 999 Namespace: "ns1", 1000 }: privateData1, 1001 privdatacommon.DigKey{ 1002 TxId: "txID1", 1003 Collection: "col2", 1004 Namespace: "ns1", 1005 }: privateData2, 1006 } 1007 1008 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig1)), 0).Return(store, true, nil) 1009 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig1)), 0).Return(store, true, nil). 1010 Run( 1011 func(arg mock.Arguments) { 1012 assert.Fail(t, "we should not fetch private data from peers where it was purged") 1013 }, 1014 ) 1015 1016 p3.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig2)), uint64(0)).Return(store, true, nil) 1017 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig2)), uint64(0)).Return(store, true, nil). 1018 Run( 1019 func(mock.Arguments) { 1020 assert.Fail(t, "we should not fetch private data of collection2 from peer 2") 1021 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 assert.NoError(t, err) 1031 assert.Equal(t, 1, len(fetchedMessages.PurgedElements)) 1032 assert.Equal(t, dig1, fetchedMessages.PurgedElements[0]) 1033 p3.PrivateDataRetriever.(*dataRetrieverMock).AssertNumberOfCalls(t, "CollectionRWSet", 1) 1034 1035 } 1036 1037 type counterDataRetreiver struct { 1038 numberOfCalls int 1039 PrivateDataRetriever 1040 } 1041 1042 func (c *counterDataRetreiver) CollectionRWSet(dig []*proto.PvtDataDigest, blockNum uint64) (Dig2PvtRWSetWithConfig, bool, error) { 1043 c.numberOfCalls += 1 1044 return c.PrivateDataRetriever.CollectionRWSet(dig, blockNum) 1045 } 1046 1047 func (c *counterDataRetreiver) getNumberOfCalls() int { 1048 return c.numberOfCalls 1049 } 1050 1051 func TestPullerIntegratedWithDataRetreiver(t *testing.T) { 1052 gn := &gossipNetwork{} 1053 1054 ns1, ns2 := "testChaincodeName1", "testChaincodeName2" 1055 col1, col2 := "testCollectionName1", "testCollectionName2" 1056 1057 ap := &mocks.CollectionAccessPolicy{} 1058 Setup(ap, 1, 2, func(data protoutil.SignedData) bool { 1059 return bytes.Equal(data.Identity, []byte("p1")) 1060 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 1061 1062 factoryMock := &mocks.CollectionAccessFactory{} 1063 factoryMock.On("AccessPolicy", mock.Anything, mock.Anything).Return(ap, nil) 1064 1065 policyStore := newCollectionStore().withPolicy(col1, uint64(1000)).thatMapsTo("p1", "p2"). 1066 withPolicy(col2, uint64(1000)).thatMapsTo("p1", "p2") 1067 1068 p1 := gn.newPuller("p1", policyStore, factoryMock, membership(peerData{"p2", uint64(10)})...) 1069 p2 := gn.newPuller("p2", policyStore, factoryMock, membership(peerData{"p1", uint64(1)})...) 1070 1071 committer := &mocks.Committer{} 1072 tempdir, err := ioutil.TempDir("", "ts") 1073 if err != nil { 1074 t.Fatalf("Failed to create test directory, got err %s", err) 1075 return 1076 } 1077 storeProvider, err := transientstore.NewStoreProvider(tempdir) 1078 if err != nil { 1079 t.Fatalf("Failed to open store, got err %s", err) 1080 return 1081 } 1082 store, err := storeProvider.OpenStore("test") 1083 if err != nil { 1084 t.Fatalf("Failed to open store, got err %s", err) 1085 return 1086 } 1087 defer storeProvider.Close() 1088 defer os.RemoveAll(tempdir) 1089 result := []*ledger.TxPvtData{ 1090 { 1091 WriteSet: &rwset.TxPvtReadWriteSet{ 1092 DataModel: rwset.TxReadWriteSet_KV, 1093 NsPvtRwset: []*rwset.NsPvtReadWriteSet{ 1094 pvtReadWriteSet(ns1, col1, []byte{1}), 1095 pvtReadWriteSet(ns1, col1, []byte{2}), 1096 }, 1097 }, 1098 SeqInBlock: 1, 1099 }, 1100 { 1101 WriteSet: &rwset.TxPvtReadWriteSet{ 1102 DataModel: rwset.TxReadWriteSet_KV, 1103 NsPvtRwset: []*rwset.NsPvtReadWriteSet{ 1104 pvtReadWriteSet(ns2, col2, []byte{3}), 1105 pvtReadWriteSet(ns2, col2, []byte{4}), 1106 }, 1107 }, 1108 SeqInBlock: 2, 1109 }, 1110 } 1111 1112 committer.On("LedgerHeight").Return(uint64(10), nil) 1113 committer.On("GetPvtDataByNum", uint64(5), mock.Anything).Return(result, nil) 1114 historyRetreiver := &mocks.ConfigHistoryRetriever{} 1115 historyRetreiver.On("MostRecentCollectionConfigBelow", mock.Anything, ns1).Return(newCollectionConfig(col1), nil) 1116 historyRetreiver.On("MostRecentCollectionConfigBelow", mock.Anything, ns2).Return(newCollectionConfig(col2), nil) 1117 committer.On("GetConfigHistoryRetriever").Return(historyRetreiver, nil) 1118 1119 dataRetreiver := &counterDataRetreiver{PrivateDataRetriever: NewDataRetriever("testchannel", store, committer), numberOfCalls: 0} 1120 p2.PrivateDataRetriever = dataRetreiver 1121 1122 dig1 := &privdatacommon.DigKey{ 1123 TxId: "txID1", 1124 Collection: col1, 1125 Namespace: ns1, 1126 BlockSeq: 5, 1127 SeqInBlock: 1, 1128 } 1129 1130 dig2 := &privdatacommon.DigKey{ 1131 TxId: "txID1", 1132 Collection: col2, 1133 Namespace: ns2, 1134 BlockSeq: 5, 1135 SeqInBlock: 2, 1136 } 1137 1138 dasf := &digestsAndSourceFactory{} 1139 d2s := dasf.mapDigest(dig1).toSources("p2").mapDigest(dig2).toSources("p2").create() 1140 fetchedMessages, err := p1.fetch(d2s) 1141 assert.NoError(t, err) 1142 assert.Equal(t, 2, len(fetchedMessages.AvailableElements)) 1143 assert.Equal(t, 1, dataRetreiver.getNumberOfCalls()) 1144 assert.Equal(t, 2, len(fetchedMessages.AvailableElements[0].Payload)) 1145 assert.Equal(t, 2, len(fetchedMessages.AvailableElements[1].Payload)) 1146 } 1147 1148 func toDigKey(dig *proto.PvtDataDigest) *privdatacommon.DigKey { 1149 return &privdatacommon.DigKey{ 1150 TxId: dig.TxId, 1151 BlockSeq: dig.BlockSeq, 1152 SeqInBlock: dig.SeqInBlock, 1153 Namespace: dig.Namespace, 1154 Collection: dig.Collection, 1155 } 1156 } 1157 1158 func TestPullerMetrics(t *testing.T) { 1159 // Scenario: p1 pulls from p2 and sends metric reports 1160 gn := &gossipNetwork{} 1161 policyStore := newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p2") 1162 factoryMock1 := &mocks.CollectionAccessFactory{} 1163 policyMock1 := &mocks.CollectionAccessPolicy{} 1164 Setup(policyMock1, 1, 2, func(data protoutil.SignedData) bool { 1165 return bytes.Equal(data.Identity, []byte("p2")) 1166 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 1167 factoryMock1.On("AccessPolicy", mock.Anything, mock.Anything).Return(policyMock1, nil) 1168 1169 testMetricProvider := gmetricsmocks.TestUtilConstructMetricProvider() 1170 metrics := metrics.NewGossipMetrics(testMetricProvider.FakeProvider).PrivdataMetrics 1171 1172 p1 := gn.newPullerWithMetrics(metrics, "p1", policyStore, factoryMock1, membership(peerData{"p2", uint64(1)})...) 1173 1174 p2TransientStore := &util.PrivateRWSetWithConfig{ 1175 RWSet: newPRWSet(), 1176 CollectionConfig: &peer.CollectionConfig{ 1177 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 1178 StaticCollectionConfig: &peer.StaticCollectionConfig{ 1179 Name: "col1", 1180 }, 1181 }, 1182 }, 1183 } 1184 policyStore = newCollectionStore().withPolicy("col1", uint64(100)).thatMapsTo("p1") 1185 factoryMock2 := &mocks.CollectionAccessFactory{} 1186 policyMock2 := &mocks.CollectionAccessPolicy{} 1187 Setup(policyMock2, 1, 2, func(data protoutil.SignedData) bool { 1188 return bytes.Equal(data.Identity, []byte("p1")) 1189 }, map[string]struct{}{"org1": {}, "org2": {}}, false) 1190 factoryMock2.On("AccessPolicy", mock.Anything, mock.Anything).Return(policyMock2, nil) 1191 1192 p2 := gn.newPullerWithMetrics(metrics, "p2", policyStore, factoryMock2) 1193 1194 dig := &proto.PvtDataDigest{ 1195 TxId: "txID1", 1196 Collection: "col1", 1197 Namespace: "ns1", 1198 } 1199 1200 store := Dig2PvtRWSetWithConfig{ 1201 privdatacommon.DigKey{ 1202 TxId: "txID1", 1203 Collection: "col1", 1204 Namespace: "ns1", 1205 }: p2TransientStore, 1206 } 1207 1208 p2.PrivateDataRetriever.(*dataRetrieverMock).On("CollectionRWSet", mock.MatchedBy(protoMatcher(dig)), 1209 uint64(0)).Return(store, true, nil) 1210 1211 dasf := &digestsAndSourceFactory{} 1212 1213 fetchedMessages, err := p1.fetch(dasf.mapDigest(toDigKey(dig)).toSources().create()) 1214 rws1 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[0]) 1215 rws2 := util.PrivateRWSet(fetchedMessages.AvailableElements[0].Payload[1]) 1216 fetched := []util.PrivateRWSet{rws1, rws2} 1217 assert.NoError(t, err) 1218 assert.Equal(t, p2TransientStore.RWSet, fetched) 1219 1220 assert.Equal(t, 1221 []string{"channel", "A"}, 1222 testMetricProvider.FakePullDuration.WithArgsForCall(0), 1223 ) 1224 assert.True(t, testMetricProvider.FakePullDuration.ObserveArgsForCall(0) > 0) 1225 assert.Equal(t, 1226 []string{"channel", "A"}, 1227 testMetricProvider.FakeRetrieveDuration.WithArgsForCall(0), 1228 ) 1229 assert.True(t, testMetricProvider.FakeRetrieveDuration.ObserveArgsForCall(0) > 0) 1230 }