@@ -167,6 +167,7 @@ func (node *peerNode) shutdown() {
167
167
168
168
type mockCommitter struct {
169
169
mock.Mock
170
+ sync.Mutex
170
171
}
171
172
172
173
func (mc * mockCommitter ) Commit (block * pcomm.Block ) error {
@@ -175,6 +176,8 @@ func (mc *mockCommitter) Commit(block *pcomm.Block) error {
175
176
}
176
177
177
178
func (mc * mockCommitter ) LedgerHeight () (uint64 , error ) {
179
+ mc .Lock ()
180
+ defer mc .Unlock ()
178
181
if mc .Called ().Get (1 ) == nil {
179
182
return mc .Called ().Get (0 ).(uint64 ), nil
180
183
}
@@ -277,6 +280,110 @@ func TestNilDirectMsg(t *testing.T) {
277
280
p .s .(* GossipStateProviderImpl ).directMessage (req )
278
281
}
279
282
283
+ func TestNilAddPayload (t * testing.T ) {
284
+ mc := & mockCommitter {}
285
+ mc .On ("LedgerHeight" , mock .Anything ).Return (uint64 (1 ), nil )
286
+ g := & mocks.GossipMock {}
287
+ g .On ("Accept" , mock .Anything , false ).Return (make (<- chan * proto.GossipMessage ), nil )
288
+ g .On ("Accept" , mock .Anything , true ).Return (nil , make (<- chan proto.ReceivedMessage ))
289
+ p := newPeerNodeWithGossip (newGossipConfig (0 ), mc , noopPeerIdentityAcceptor , g )
290
+ defer p .shutdown ()
291
+ err := p .s .AddPayload (nil )
292
+ assert .Error (t , err )
293
+ assert .Contains (t , err .Error (), "nil" )
294
+ }
295
+
296
+ func TestAddPayloadLedgerUnavailable (t * testing.T ) {
297
+ mc := & mockCommitter {}
298
+ mc .On ("LedgerHeight" , mock .Anything ).Return (uint64 (1 ), nil )
299
+ g := & mocks.GossipMock {}
300
+ g .On ("Accept" , mock .Anything , false ).Return (make (<- chan * proto.GossipMessage ), nil )
301
+ g .On ("Accept" , mock .Anything , true ).Return (nil , make (<- chan proto.ReceivedMessage ))
302
+ p := newPeerNodeWithGossip (newGossipConfig (0 ), mc , noopPeerIdentityAcceptor , g )
303
+ defer p .shutdown ()
304
+ // Simulate a problem in the ledger
305
+ failedLedger := mock.Mock {}
306
+ failedLedger .On ("LedgerHeight" , mock .Anything ).Return (uint64 (0 ), errors .New ("cannot query ledger" ))
307
+ mc .Lock ()
308
+ mc .Mock = failedLedger
309
+ mc .Unlock ()
310
+
311
+ rawblock := pcomm .NewBlock (uint64 (1 ), []byte {})
312
+ b , _ := pb .Marshal (rawblock )
313
+ err := p .s .AddPayload (& proto.Payload {
314
+ SeqNum : uint64 (1 ),
315
+ Data : b ,
316
+ })
317
+ assert .Error (t , err )
318
+ assert .Contains (t , err .Error (), "Failed obtaining ledger height" )
319
+ assert .Contains (t , err .Error (), "cannot query ledger" )
320
+ }
321
+
322
+ func TestOverPopulation (t * testing.T ) {
323
+ // Scenario: Add to the state provider blocks
324
+ // with a gap in between, and ensure that the payload buffer
325
+ // rejects blocks starting if the distance between the ledger height to the latest
326
+ // block it contains is bigger than defMaxBlockDistance.
327
+
328
+ mc := & mockCommitter {}
329
+ blocksPassedToLedger := make (chan uint64 , 10 )
330
+ mc .On ("Commit" , mock .Anything ).Run (func (arg mock.Arguments ) {
331
+ blocksPassedToLedger <- arg .Get (0 ).(* pcomm.Block ).Header .Number
332
+ })
333
+ mc .On ("LedgerHeight" , mock .Anything ).Return (uint64 (1 ), nil )
334
+ g := & mocks.GossipMock {}
335
+ g .On ("Accept" , mock .Anything , false ).Return (make (<- chan * proto.GossipMessage ), nil )
336
+ g .On ("Accept" , mock .Anything , true ).Return (nil , make (<- chan proto.ReceivedMessage ))
337
+ p := newPeerNode (newGossipConfig (0 ), mc , noopPeerIdentityAcceptor )
338
+ defer p .shutdown ()
339
+
340
+ // Add some blocks in a sequential manner and make sure it works
341
+ for i := 1 ; i <= 4 ; i ++ {
342
+ rawblock := pcomm .NewBlock (uint64 (i ), []byte {})
343
+ b , _ := pb .Marshal (rawblock )
344
+ assert .NoError (t , p .s .AddPayload (& proto.Payload {
345
+ SeqNum : uint64 (i ),
346
+ Data : b ,
347
+ }))
348
+ }
349
+
350
+ // Add payloads from 10 to defMaxBlockDistance, while we're missing blocks [5,9]
351
+ // Should succeed
352
+ for i := 10 ; i <= defMaxBlockDistance ; i ++ {
353
+ rawblock := pcomm .NewBlock (uint64 (i ), []byte {})
354
+ b , _ := pb .Marshal (rawblock )
355
+ assert .NoError (t , p .s .AddPayload (& proto.Payload {
356
+ SeqNum : uint64 (i ),
357
+ Data : b ,
358
+ }))
359
+ }
360
+
361
+ // Add payloads from defMaxBlockDistance + 2 to defMaxBlockDistance * 10
362
+ // Should fail.
363
+ for i := defMaxBlockDistance + 1 ; i <= defMaxBlockDistance * 10 ; i ++ {
364
+ rawblock := pcomm .NewBlock (uint64 (i ), []byte {})
365
+ b , _ := pb .Marshal (rawblock )
366
+ assert .Error (t , p .s .AddPayload (& proto.Payload {
367
+ SeqNum : uint64 (i ),
368
+ Data : b ,
369
+ }))
370
+ }
371
+
372
+ // Ensure only blocks 1-4 were passed to the ledger
373
+ close (blocksPassedToLedger )
374
+ i := 1
375
+ for seq := range blocksPassedToLedger {
376
+ assert .Equal (t , uint64 (i ), seq )
377
+ i ++
378
+ }
379
+ assert .Equal (t , 5 , i )
380
+
381
+ // Ensure we don't store too many blocks in memory
382
+ sp := p .s .(* GossipStateProviderImpl )
383
+ assert .True (t , sp .payloads .Size () < defMaxBlockDistance )
384
+
385
+ }
386
+
280
387
func TestFailures (t * testing.T ) {
281
388
mc := & mockCommitter {}
282
389
mc .On ("LedgerHeight" , mock .Anything ).Return (uint64 (0 ), nil )
0 commit comments