@@ -313,6 +313,103 @@ func TestChannelPeriodicalPublishStateInfo(t *testing.T) {
313
313
gc .Stop ()
314
314
}
315
315
316
+ func TestChannelMsgStoreEviction (t * testing.T ) {
317
+ t .Parallel ()
318
+ // Scenario: Create 4 phases in which the pull mediator of the channel would receive blocks
319
+ // via pull.
320
+ // The total amount of blocks should be restricted by the capacity of the message store.
321
+ // After the pull phases end, we ensure that only the latest blocks are preserved in the pull
322
+ // mediator, and the old blocks were evicted.
323
+ // We test this by sending a hello message to the pull mediator and inspecting the digest message
324
+ // returned as a response.
325
+
326
+ cs := & cryptoService {}
327
+ cs .On ("VerifyBlock" , mock .Anything ).Return (nil )
328
+ adapter := new (gossipAdapterMock )
329
+ configureAdapter (adapter , discovery.NetworkMember {PKIid : pkiIDInOrg1 })
330
+ adapter .On ("Gossip" , mock .Anything )
331
+ adapter .On ("DeMultiplex" , mock .Anything ).Run (func (arg mock.Arguments ) {
332
+ })
333
+
334
+ gc := NewGossipChannel (pkiIDInOrg1 , orgInChannelA , cs , channelA , adapter , & joinChanMsg {})
335
+ defer gc .Stop ()
336
+ gc .HandleMessage (& receivedMsg {PKIID : pkiIDInOrg1 , msg : createStateInfoMsg (100 , pkiIDInOrg1 , channelA )})
337
+
338
+ var wg sync.WaitGroup
339
+
340
+ msgsPerPhase := uint64 (50 )
341
+ lastPullPhase := make (chan uint64 , msgsPerPhase )
342
+ totalPhases := uint64 (4 )
343
+ phaseNum := uint64 (0 )
344
+ wg .Add (int (totalPhases ))
345
+
346
+ adapter .On ("Send" , mock .Anything , mock .Anything ).Run (func (args mock.Arguments ) {
347
+ msg := args .Get (0 ).(* proto.SignedGossipMessage )
348
+ // Ignore all other messages sent like StateInfo messages
349
+ if ! msg .IsPullMsg () {
350
+ return
351
+ }
352
+ // Stop the pull when we reach the final phase
353
+ if atomic .LoadUint64 (& phaseNum ) == totalPhases && msg .IsHelloMsg () {
354
+ return
355
+ }
356
+
357
+ start := atomic .LoadUint64 (& phaseNum ) * msgsPerPhase
358
+ end := start + msgsPerPhase
359
+ if msg .IsHelloMsg () {
360
+ // Advance phase
361
+ atomic .AddUint64 (& phaseNum , uint64 (1 ))
362
+ }
363
+
364
+ // Create and execute the current phase of pull
365
+ currSeq := sequence (start , end )
366
+ pullPhase := simulatePullPhase (gc , t , & wg , func (envelope * proto.Envelope ) {}, currSeq ... )
367
+ pullPhase (args )
368
+
369
+ // If we finished the last phase, save the sequence to be used later for inspection
370
+ if msg .IsDataReq () && atomic .LoadUint64 (& phaseNum ) == totalPhases {
371
+ for _ , seq := range currSeq {
372
+ lastPullPhase <- seq
373
+ }
374
+ close (lastPullPhase )
375
+ }
376
+ })
377
+ // Wait for all pull phases to end
378
+ wg .Wait ()
379
+
380
+ msgSentFromPullMediator := make (chan * proto.GossipMessage , 1 )
381
+
382
+ helloMsg := createHelloMsg (pkiIDInOrg1 )
383
+ helloMsg .On ("Respond" , mock .Anything ).Run (func (arg mock.Arguments ) {
384
+ msg := arg .Get (0 ).(* proto.GossipMessage )
385
+ if ! msg .IsDigestMsg () {
386
+ return
387
+ }
388
+ msgSentFromPullMediator <- msg
389
+ })
390
+ gc .HandleMessage (helloMsg )
391
+ select {
392
+ case msg := <- msgSentFromPullMediator :
393
+ // This is just to check that we responded with a digest on time.
394
+ // Put message back into the channel for further inspection
395
+ msgSentFromPullMediator <- msg
396
+ case <- time .After (time .Second * 5 ):
397
+ t .Fatal ("Didn't reply with a digest on time" )
398
+ }
399
+ // Only 1 digest sent
400
+ assert .Len (t , msgSentFromPullMediator , 1 )
401
+ msg := <- msgSentFromPullMediator
402
+ // It's a digest and not anything else, like an update
403
+ assert .True (t , msg .IsDigestMsg ())
404
+ assert .Len (t , msg .GetDataDig ().Digests , adapter .GetConf ().MaxBlockCountToStore + 1 )
405
+ // Check that the last sequences are kept.
406
+ // Since we checked the length, it proves that the old blocks were discarded, since we had much more
407
+ // total blocks overall than our capacity
408
+ for seq := range lastPullPhase {
409
+ assert .Contains (t , msg .GetDataDig ().Digests , fmt .Sprintf ("%d" , seq ))
410
+ }
411
+ }
412
+
316
413
func TestChannelPull (t * testing.T ) {
317
414
t .Parallel ()
318
415
cs := & cryptoService {}
@@ -334,7 +431,7 @@ func TestChannelPull(t *testing.T) {
334
431
go gc .HandleMessage (& receivedMsg {PKIID : pkiIDInOrg1 , msg : createStateInfoMsg (100 , pkiIDInOrg1 , channelA )})
335
432
336
433
var wg sync.WaitGroup
337
- pullPhase := simulatePullPhase (gc , t , & wg , func (envelope * proto.Envelope ) {})
434
+ pullPhase := simulatePullPhase (gc , t , & wg , func (envelope * proto.Envelope ) {}, 10 , 11 )
338
435
adapter .On ("Send" , mock .Anything , mock .Anything ).Run (pullPhase )
339
436
340
437
wg .Wait ()
@@ -696,7 +793,7 @@ func TestChannelPulledBadBlocks(t *testing.T) {
696
793
env .Payload = sMsg .NoopSign ().Payload
697
794
}
698
795
699
- pullPhase1 := simulatePullPhase (gc , t , & wg , changeChan )
796
+ pullPhase1 := simulatePullPhase (gc , t , & wg , changeChan , 10 , 11 )
700
797
adapter .On ("Send" , mock .Anything , mock .Anything ).Run (pullPhase1 )
701
798
adapter .On ("DeMultiplex" , mock .Anything )
702
799
wg .Wait ()
@@ -718,7 +815,7 @@ func TestChannelPulledBadBlocks(t *testing.T) {
718
815
noop := func (env * proto.Envelope ) {
719
816
720
817
}
721
- pullPhase2 := simulatePullPhase (gc , t , & wg2 , noop )
818
+ pullPhase2 := simulatePullPhase (gc , t , & wg2 , noop , 10 , 11 )
722
819
adapter .On ("Send" , mock .Anything , mock .Anything ).Run (pullPhase2 )
723
820
wg2 .Wait ()
724
821
assert .Equal (t , 0 , gc .(* gossipChannel ).blockMsgStore .Size ())
@@ -740,7 +837,7 @@ func TestChannelPulledBadBlocks(t *testing.T) {
740
837
sMsg .GossipMessage .GetDataMsg ().Payload = nil
741
838
env .Payload = sMsg .NoopSign ().Payload
742
839
}
743
- pullPhase3 := simulatePullPhase (gc , t , & wg3 , emptyBlock )
840
+ pullPhase3 := simulatePullPhase (gc , t , & wg3 , emptyBlock , 10 , 11 )
744
841
adapter .On ("Send" , mock .Anything , mock .Anything ).Run (pullPhase3 )
745
842
wg3 .Wait ()
746
843
assert .Equal (t , 0 , gc .(* gossipChannel ).blockMsgStore .Size ())
@@ -763,7 +860,7 @@ func TestChannelPulledBadBlocks(t *testing.T) {
763
860
sMsg .Content = createHelloMsg (pkiIDInOrg1 ).GetGossipMessage ().Content
764
861
env .Payload = sMsg .NoopSign ().Payload
765
862
}
766
- pullPhase4 := simulatePullPhase (gc , t , & wg4 , nonBlockMsg )
863
+ pullPhase4 := simulatePullPhase (gc , t , & wg4 , nonBlockMsg , 10 , 11 )
767
864
adapter .On ("Send" , mock .Anything , mock .Anything ).Run (pullPhase4 )
768
865
wg4 .Wait ()
769
866
assert .Equal (t , 0 , gc .(* gossipChannel ).blockMsgStore .Size ())
@@ -1253,19 +1350,23 @@ func TestOnDemandGossip(t *testing.T) {
1253
1350
}
1254
1351
}
1255
1352
1256
- func createDataUpdateMsg (nonce uint64 ) * proto.SignedGossipMessage {
1257
- return ( & proto.GossipMessage {
1353
+ func createDataUpdateMsg (nonce uint64 , seqs ... uint64 ) * proto.SignedGossipMessage {
1354
+ msg := & proto.GossipMessage {
1258
1355
Nonce : 0 ,
1259
1356
Channel : []byte (channelA ),
1260
1357
Tag : proto .GossipMessage_CHAN_AND_ORG ,
1261
1358
Content : & proto.GossipMessage_DataUpdate {
1262
1359
DataUpdate : & proto.DataUpdate {
1263
1360
MsgType : proto .PullMsgType_BLOCK_MSG ,
1264
1361
Nonce : nonce ,
1265
- Data : []* proto.Envelope {createDataMsg ( 10 , channelA ). Envelope , createDataMsg ( 11 , channelA ). Envelope },
1362
+ Data : []* proto.Envelope {},
1266
1363
},
1267
1364
},
1268
- }).NoopSign ()
1365
+ }
1366
+ for _ , seq := range seqs {
1367
+ msg .GetDataUpdate ().Data = append (msg .GetDataUpdate ().Data , createDataMsg (seq , channelA ).Envelope )
1368
+ }
1369
+ return (msg ).NoopSign ()
1269
1370
}
1270
1371
1271
1372
func createHelloMsg (PKIID common.PKIidType ) * receivedMsg {
@@ -1348,7 +1449,7 @@ func createDataMsg(seqnum uint64, channel common.ChainID) *proto.SignedGossipMes
1348
1449
}).NoopSign ()
1349
1450
}
1350
1451
1351
- func simulatePullPhase (gc GossipChannel , t * testing.T , wg * sync.WaitGroup , mutator msgMutator ) func (args mock.Arguments ) {
1452
+ func simulatePullPhase (gc GossipChannel , t * testing.T , wg * sync.WaitGroup , mutator msgMutator , seqs ... uint64 ) func (args mock.Arguments ) {
1352
1453
var l sync.Mutex
1353
1454
var sentHello bool
1354
1455
var sentReq bool
@@ -1386,11 +1487,21 @@ func simulatePullPhase(gc GossipChannel, t *testing.T, wg *sync.WaitGroup, mutat
1386
1487
// from the imaginary peer that got the request
1387
1488
dataUpdateMsg := new (receivedMsg )
1388
1489
dataUpdateMsg .PKIID = pkiIDInOrg1
1389
- dataUpdateMsg .msg = createDataUpdateMsg (dataReq .Nonce )
1490
+ dataUpdateMsg .msg = createDataUpdateMsg (dataReq .Nonce , seqs ... )
1390
1491
mutator (dataUpdateMsg .msg .GetDataUpdate ().Data [0 ])
1391
1492
gc .HandleMessage (dataUpdateMsg )
1392
1493
wg .Done ()
1393
1494
}
1394
1495
}
1496
+ }
1497
+
1498
+ func sequence (start uint64 , end uint64 ) []uint64 {
1499
+ sequence := make ([]uint64 , end - start + 1 )
1500
+ i := 0
1501
+ for n := start ; n <= end ; n ++ {
1502
+ sequence [i ] = n
1503
+ i ++
1504
+ }
1505
+ return sequence
1395
1506
1396
1507
}
0 commit comments