mirror of
https://github.com/rightup/pyMC_Repeater.git
synced 2026-05-03 04:02:15 +02:00
Before this change, calculate_packet_hash() (SHA-256 + hex + upper) was called 3 times per forwarded packet and 4 times per dropped packet: __call__ → pkt_hash_full = packet.calculate_packet_hash() #1 → flood/direct_forward → is_duplicate → calculate_packet_hash() #2 → flood/direct_forward → mark_seen → calculate_packet_hash() #3 (drop) → _get_drop_reason → is_duplicate → calculate_packet_hash() #4 pkt_hash_full was computed in __call__ but never threaded down into process_packet, flood_forward, direct_forward, is_duplicate, or _get_drop_reason. Each method recomputed it independently. Fix: add optional packet_hash: Optional[str] = None to is_duplicate, _get_drop_reason, flood_forward, direct_forward, and process_packet. Pass pkt_hash_full from __call__ through the chain. Each method uses the provided hash or falls back to computing it — preserving backward compatibility for external callers (TraceHelper, etc.) that have no pre-computed hash. Result: 1 SHA-256 computation per packet in the hot path regardless of whether the packet is forwarded or dropped. Also adds explicit INVARIANT docstrings to flood_forward, direct_forward, and is_duplicate documenting that these methods must remain synchronous (no await). The is_duplicate + mark_seen pair is atomic within the asyncio event loop; adding an await between them would allow two concurrent tasks to both pass the duplicate check for the same packet — forwarding it twice. Docs: docs/pr_hash_once.md — problem analysis, call-chain diagram, per-method diffs, quantification (~3-8 µs saved per packet), test plan (including hash-count assertion), and proof that passing the original's hash to the deep-copied packet is correct. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>