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

Function TestHashMemoryExhaustionAttack

protocols/cpc/fetcher/fetcher_test.go:643–685  ·  view source on GitHub ↗

Tests that a peer is unable to use unbounded memory with sending infinite block announcements to a node, but that even in the face of such an attack, the fetcher remains operational.

(t *testing.T)

Source from the content-addressed store, hash-verified

641// block announcements to a node, but that even in the face of such an attack,
642// the fetcher remains operational.
643func TestHashMemoryExhaustionAttack(t *testing.T) {
644 // Create a tester with instrumented import hooks
645 tester := newTester()
646
647 imported, announces := make(chan *types.Block), int32(0)
648 tester.fetcher.importedHook = func(block *types.Block) { imported <- block }
649 tester.fetcher.announceChangeHook = func(hash common.Hash, added bool) {
650 if added {
651 atomic.AddInt32(&announces, 1)
652 } else {
653 atomic.AddInt32(&announces, -1)
654 }
655 }
656 // Create a valid chain and an infinite junk chain
657 targetBlocks := hashLimit + 2*maxQueueDist
658 hashes, blocks := makeChain(targetBlocks, 0, genesis)
659 validHeaderFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack)
660 validBodyFetcher := tester.makeBodyFetcher("valid", blocks, 0)
661
662 attack, _ := makeChain(targetBlocks, 0, unknownBlock)
663 attackerHeaderFetcher := tester.makeHeaderFetcher("attacker", nil, -gatherSlack)
664 attackerBodyFetcher := tester.makeBodyFetcher("attacker", nil, 0)
665
666 // Feed the tester a huge hashset from the attacker, and a limited from the valid peer
667 for i := 0; i < len(attack); i++ {
668 if i < maxQueueDist {
669 tester.fetcher.Notify("valid", hashes[len(hashes)-2-i], uint64(i+1), time.Now(), validHeaderFetcher, validBodyFetcher)
670 }
671 tester.fetcher.Notify("attacker", attack[i], 1 /* don't distance drop */, time.Now(), attackerHeaderFetcher, attackerBodyFetcher)
672 }
673 if count := atomic.LoadInt32(&announces); count != hashLimit+maxQueueDist {
674 t.Fatalf("queued announce count mismatch: have %d, want %d", count, hashLimit+maxQueueDist)
675 }
676 // Wait for fetches to complete
677 verifyImportCount(t, imported, maxQueueDist)
678
679 // Feed the remaining valid hashes to ensure DOS protection state remains clean
680 for i := len(hashes) - maxQueueDist - 2; i >= 0; i-- {
681 tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), validHeaderFetcher, validBodyFetcher)
682 verifyImportEvent(t, imported, true)
683 }
684 verifyImportDone(t, imported)
685}
686
687// Tests that blocks sent to the fetcher (either through propagation or via hash
688// announces and retrievals) don't pile up indefinitely, exhausting available

Callers

nothing calls this directly

Calls 10

newTesterFunction · 0.85
makeChainFunction · 0.85
verifyImportCountFunction · 0.85
verifyImportEventFunction · 0.85
verifyImportDoneFunction · 0.85
makeHeaderFetcherMethod · 0.80
makeBodyFetcherMethod · 0.80
NowMethod · 0.65
AddMethod · 0.65
NotifyMethod · 0.45

Tested by

no test coverage detected