pyblock/pybitblock/tui/workers/data_fetcher.py
GaltRanch 893aabc85d Security audit round 2: eliminate shell=True, mask secrets, fix race conditions
- Replace all shell=True subprocess calls with Python-native processing
  (nodeconnection.py, SPV/nodeconnection.py, SPV/ppi.py)
- Mask sensitive inputs (private keys, passwords, tokens) with getpass
- Add threading.Lock to block_explorer.py shared state
- Use json.loads() instead of fragile string splitting in apisnd.py
- Add path validation before file open in apisnd.py
- Replace random.randint with secrets.randbelow for mining nonces
- Fix destructive exception handlers in clone.py and feed.py
- Replace bare except clauses with specific exceptions + logging
- Remove unused imports (psutil, xmltodict, block_visualizer, base64, say)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 11:15:59 -03:00

76 lines
2.5 KiB
Python

"""Async data workers for fetching Bitcoin data."""
import requests
def fetch_block_height():
"""Fetch current block height from mempool.space."""
try:
r = requests.get("https://mempool.space/api/blocks/tip/height", timeout=5)
return str(r.json())
except (requests.RequestException, ValueError, KeyError):
return "---"
def fetch_btc_price():
"""Fetch current BTC/USD price from mempool.space."""
try:
r = requests.get("https://mempool.space/api/v1/prices", timeout=5)
price = r.json().get("USD", 0)
return f"{price:,}"
except (requests.RequestException, ValueError, KeyError):
return "---"
def fetch_fees():
"""Fetch recommended fees from mempool.space."""
try:
r = requests.get("https://mempool.space/api/v1/fees/recommended", timeout=5)
return r.json()
except (requests.RequestException, ValueError, KeyError):
return {"fastestFee": "?", "halfHourFee": "?", "hourFee": "?"}
def fetch_mempool_info():
"""Fetch mempool summary."""
try:
r = requests.get("https://mempool.space/api/mempool", timeout=5)
data = r.json()
return {
"count": data.get("count", 0),
"vsize": data.get("vsize", 0),
"total_fee": data.get("total_fee", 0),
}
except (requests.RequestException, ValueError, KeyError):
return {"count": "?", "vsize": "?", "total_fee": "?"}
def fetch_latest_blocks():
"""Fetch latest 5 blocks from mempool.space."""
try:
r = requests.get("https://mempool.space/api/v1/blocks", timeout=5)
blocks = r.json()[:5]
return [
{
"height": b.get("height", "?"),
"tx_count": b.get("tx_count", "?"),
"size": round(b.get("size", 0) / 1_000_000, 2),
"pool": b.get("extras", {}).get("pool", {}).get("name", "Unknown"),
}
for b in blocks
]
except (requests.RequestException, ValueError, KeyError):
return []
def fetch_hashrate():
"""Fetch network hashrate info."""
try:
r = requests.get("https://mempool.space/api/v1/mining/hashrate/3d", timeout=5)
data = r.json()
current = data.get("currentHashrate", 0)
difficulty = data.get("currentDifficulty", 0)
eh = current / 1e18
return {"hashrate_eh": f"{eh:.1f}", "difficulty": f"{difficulty:.2e}"}
except (requests.RequestException, ValueError, KeyError):
return {"hashrate_eh": "?", "difficulty": "?"}