Metadata-Version: 2.4
Name: djinn-tunnel-shield
Version: 0.1.0
Summary: Zero-config DDoS protection for Bittensor miners via Cloudflare Tunnel
License: MIT
Requires-Python: >=3.10
Requires-Dist: eciespy>=0.4.1
Requires-Dist: structlog>=23.0
Provides-Extra: bittensor
Requires-Dist: bittensor>=7.0; extra == 'bittensor'
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Description-Content-Type: text/markdown

# djinn-tunnel-shield

Zero-config DDoS protection for Bittensor miners via Cloudflare Tunnel.

## Install

```bash
pip install djinn-tunnel-shield
```

## Miner (3 lines)

```python
from djinn_tunnel_shield import MinerShield

shield = MinerShield(wallet, subtensor, netuid, port=8422)
asyncio.create_task(shield.run())

# In your health endpoint, include: {"tunnel_url": shield.tunnel_url}
```

**Without `CLOUDFLARE_TOKEN`**: emergency quick tunnel activates only when DDoS is detected (validator pings go silent). Logs a warning to set up a permanent tunnel.

**With `CLOUDFLARE_TOKEN`**: permanent named tunnel, stable URL, fully TOS-compliant.

## Validator (3 lines)

```python
from djinn_tunnel_shield import ShieldResolver

resolver = ShieldResolver(wallet=wallet)

# In health check, after parsing response:
resolver.cache_from_health(uid, health_data)

# When connecting to a miner:
for url in resolver.urls(uid, ip, port, "/health"):
    try:
        resp = await client.get(url)
        resolver.record_success(uid)
        break
    except Exception:
        resolver.record_failure(uid)
```

The resolver tries direct IP first. After consecutive failures, it switches to the cached tunnel URL. Periodically probes direct IP to detect recovery.

## How it works

1. Miner starts a Cloudflare Tunnel (quick or named)
2. Tunnel URL is encrypted per-validator (ECIES) and committed on-chain
3. Validators decrypt the URL and cache it
4. On direct-IP failure (DDoS), validators route through the tunnel
5. Cloudflare absorbs the volumetric attack; miner stays reachable

## Configuration

```python
from djinn_tunnel_shield import ShieldConfig

config = ShieldConfig(
    expected_ping_interval=12.0,  # seconds between validator pings
    min_missed_pings=5,           # consecutive misses before DDoS detection
    recovery_cooldown=300.0,      # seconds of stable pings before deactivating
    recommit_interval=3600.0,     # re-commit URL on-chain every hour
    direct_failure_threshold=2,   # switch to tunnel after N direct-IP failures
    direct_probe_interval=300.0,  # probe direct IP every 5 min while in tunnel mode
)
```

## License

MIT
