MCPcopy Create free account
hub / github.com/CPChain/chain / TestBlockMemoryExhaustionAttack

Function TestBlockMemoryExhaustionAttack

protocols/cpc/fetcher/fetcher_test.go:690–739  ·  view source on GitHub ↗

Tests that blocks sent to the fetcher (either through propagation or via hash announces and retrievals) don't pile up indefinitely, exhausting available system memory.

(t *testing.T)

Source from the content-addressed store, hash-verified

688// announces and retrievals) don't pile up indefinitely, exhausting available
689// system memory.
690func TestBlockMemoryExhaustionAttack(t *testing.T) {
691 // Create a tester with instrumented import hooks
692 tester := newTester()
693
694 imported, enqueued := make(chan *types.Block), int32(0)
695 tester.fetcher.importedHook = func(block *types.Block) { imported <- block }
696 tester.fetcher.queueChangeHook = func(hash common.Hash, added bool) {
697 if added {
698 atomic.AddInt32(&enqueued, 1)
699 } else {
700 atomic.AddInt32(&enqueued, -1)
701 }
702 }
703 // Create a valid chain and a batch of dangling (but in range) blocks
704 targetBlocks := hashLimit + 2*maxQueueDist
705 hashes, blocks := makeChain(targetBlocks, 0, genesis)
706 attack := make(map[common.Hash]*types.Block)
707 for i := byte(0); len(attack) < blockLimit+2*maxQueueDist; i++ {
708 hashes, blocks := makeChain(maxQueueDist-1, i, unknownBlock)
709 for _, hash := range hashes[:maxQueueDist-2] {
710 attack[hash] = blocks[hash]
711 }
712 }
713 // Try to feed all the attacker blocks make sure only a limited batch is accepted
714 for _, block := range attack {
715 tester.fetcher.Enqueue("attacker", block)
716 }
717 time.Sleep(200 * time.Millisecond)
718 if queued := atomic.LoadInt32(&enqueued); queued != blockLimit {
719 t.Fatalf("queued block count mismatch: have %d, want %d", queued, blockLimit)
720 }
721 // Queue up a batch of valid blocks, and check that a new peer is allowed to do so
722 for i := 0; i < maxQueueDist-1; i++ {
723 tester.fetcher.Enqueue("valid", blocks[hashes[len(hashes)-3-i]])
724 }
725 time.Sleep(100 * time.Millisecond)
726 if queued := atomic.LoadInt32(&enqueued); queued != blockLimit+maxQueueDist-1 {
727 t.Fatalf("queued block count mismatch: have %d, want %d", queued, blockLimit+maxQueueDist-1)
728 }
729 // Insert the missing piece (and sanity check the import)
730 tester.fetcher.Enqueue("valid", blocks[hashes[len(hashes)-2]])
731 verifyImportCount(t, imported, maxQueueDist)
732
733 // Insert the remaining blocks in chunks to ensure clean DOS protection
734 for i := maxQueueDist; i < len(hashes)-1; i++ {
735 tester.fetcher.Enqueue("valid", blocks[hashes[len(hashes)-2-i]])
736 verifyImportEvent(t, imported, true)
737 }
738 verifyImportDone(t, imported)
739}

Callers

nothing calls this directly

Calls 7

newTesterFunction · 0.85
makeChainFunction · 0.85
verifyImportCountFunction · 0.85
verifyImportEventFunction · 0.85
verifyImportDoneFunction · 0.85
EnqueueMethod · 0.80
SleepMethod · 0.80

Tested by

no test coverage detected