TxFetcher.Notify is the entry point for every NewPooledTransactionHashes
message: for a well-connected node with dozens of peers it fires
thousands of times per second. On a warm mempool nearly every announced
hash is already known, because some earlier peer already pushed it, so
the "unknown" filter reduces the batch to nothing.
The function still paid `2 * make([]T, 0, len(hashes))` upfront on every
call, wasting ~32B * len(hashes) per slice × 2 slices (common.Hash is
32B, txMetadata is 2B but aligned). At 256-hash announcements that is
10 KiB of allocator pressure per call for nothing to show for it.
Mirror the lazy-allocation pattern applied to scheduleFetches in
2ca74d2ef ("eth/fetcher: lazy-allocate hashes slice in
scheduleFetches"): defer the allocation to the first append, and size
to `len(hashes)-i` so the capacity is right-sized when a late-arriving
fresh hash is the only one we keep.
Benchmark (Apple M4 Pro, 256-hash batch, benchstat of 3 samples):
scenario ns/op B/op allocs/op
AllKnown 2670 → 1915 10240 → 0 2 → 0 (-28% / -100% / -100%)
HalfNew 4873 → 4968 10304 → 10304 3 → 3 (noise)
AllNew 5932 → 5982 10304 → 10304 3 → 3 (noise)
AllKnown is the steady-state case. HalfNew and AllNew guard against
regressing the cold path; both stay within measurement noise.