[Bug] WebSocket Streams: stream registry is global, two clients with the same stream name get each other's data
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 88/100
Direzione di ricerca
Inizia in common/src/binance_common/websocket.py con WebSocketStreamBase: trova le mappe a livello di modulo global_stream_connections e global_user_stream_connections, poi ogni punto in cui vengono lette o scritte — il filtro di subscribe, on, l'unsubscribe e la pulizia durante la riconnessione — e spostale in attributi per istanza inizializzati in __init__. Esegui prima lo script di riproduzione aiohttp autosufficiente riportato nel corpo dell'issue per confermare l'output errato, poi rieseguilo per verificare che ogni server riceva il proprio SUBSCRIBE e che fut_cb riceva {'venue': 'futures'}. Controlla che i test websocket esistenti del repo passino ancora, poiché la logica di pooling e deduplicazione dipende da questo registro.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Summary
WebSocketStreamBase keeps its stream-to-connection registry in two module-level objects (global_stream_connections, global_user_stream_connections in common/src/binance_common/websocket.py). Every client in the process shares them, keyed only by stream name.
Spot and USDⓈ-M Futures use the same stream names (btcusdt@aggTrade, btcusdt@depth, ...), and so do mainnet and testnet. When two stream clients in one process subscribe to the same name:
- the second client never sends
SUBSCRIBE, because the name is already registered; - its callback is attached to the first client's connection, so it receives the other venue's data, with no error.
Reproduce
Self-contained: one local aiohttp server with two endpoints standing in for two venues; each tags its messages with its name. binance-common==4.5.1 (same as master at 43f19a9), Python 3.13.
import asyncio, json, logging
from aiohttp import web
from binance_common.configuration import ConfigurationWebSocketStreams
from binance_common.websocket import WebSocketStreamBase, RequestStream
logging.disable(logging.CRITICAL)
subs = {"spot": [], "futures": []}
def mk(name):
async def handler(request):
ws = web.WebSocketResponse(); await ws.prepare(request)
async for msg in ws:
d = json.loads(msg.data)
if d["method"] == "SUBSCRIBE":
subs[name] += d["params"]
await ws.send_json({"id": d["id"], "result": None})
for s in d["params"]:
await ws.send_json({"stream": s, "data": {"venue": name}})
return ws
return handler
async def main():
app = web.Application()
app.router.add_get("/spot/stream", mk("spot")); app.router.add_get("/fut/stream", mk("futures"))
r = web.AppRunner(app); await r.setup(); await web.TCPSite(r, "127.0.0.1", 18766).start()
spot = WebSocketStreamBase(ConfigurationWebSocketStreams(stream_url="ws://127.0.0.1:18766/spot/stream"))
fut = WebSocketStreamBase(ConfigurationWebSocketStreams(stream_url="ws://127.0.0.1:18766/fut/stream"))
await spot.create_connection(); await fut.create_connection()
got = {"spot_cb": [], "fut_cb": []}
h1 = await RequestStream(spot, "btcusdt@aggTrade"); h1.on("message", lambda d: got["spot_cb"].append(d))
h2 = await RequestStream(fut, "btcusdt@aggTrade"); h2.on("message", lambda d: got["fut_cb"].append(d))
await asyncio.sleep(0.5)
print("SUBSCRIBE frames received by servers:", subs)
print("callback payloads:", got)
await spot.close_connection(); await fut.close_connection(); await r.cleanup()
asyncio.run(main())
Output:
SUBSCRIBE frames received by servers: {'spot': ['btcusdt@aggTrade'], 'futures': []}
callback payloads: {'spot_cb': [{'stream': 'btcusdt@aggTrade', 'data': {'venue': 'spot'}}], 'fut_cb': [{'stream': 'btcusdt@aggTrade', 'data': {'venue': 'spot'}}]}
Expected
Each server receives its own SUBSCRIBE, and fut_cb receives {'venue': 'futures'}.
Impact
A process that follows the same symbol on Spot and Futures (basis or arbitrage monitoring, for example) gets Spot trades delivered to the Futures handler. Nothing is logged, and the payload shapes are close enough that it is easy to miss.
Suggested fix
Make both maps instance attributes created in the client's __init__ and use them wherever the globals are referenced today (subscribe filter, on, unsubscribe and the reconnect cleanup). Streams would then be deduplicated per client, which is what the pooling logic needs.
- Lingua principale
- Python
- Stelle
- 2.9k
- Fork
- 707
- Merge medio
- 2h 17m
- PR unite (30g)
- 2
Preparare l'ambiente
Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di binance/binance-connector-python
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
binance/binance-connector-python#514 · 1 commento ·
-
[Bug] WebSocket API: session re-logon after reconnect is sent without apiKey and signatureForse già presa @Amadeus-22 l’ha presa 2 giorni fa. Aperta
Difficoltà 3/5 1-3 ore Idoneità per principianti 74/100
-
[Bug] Response models declare numeric fields as strict `str`, causing silent fallback of `.data()` to raw dict (simple-earn & staking)Forse già presa @Tyagiquamar l’ha presa 24 giorni fa. Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 68/100
binance/binance-connector-python#553 · 2 commenti ·
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 20/100
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 30/100
binance/binance-connector-python#464 · 1 commento · 5 reazioni ·
Tutte le issue di binance/binance-connector-python
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
huggingface/peft#3955 ·
I maintainer di solito rispondono entro 1 giorno
-
author-page correction
Difficoltà 2/5 1-3 ore Idoneità per principianti 60/100
acl-org/acl-anthology#10313 ·
I maintainer di solito rispondono entro 1 giorno
-
anime duplicate exception request-theme
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 82/100
LizardByte/ThemerrDB#8926 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
huggingface/transformers#49556 ·
I maintainer di solito rispondono entro 1 giorno
-
area/security bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
mozilla-ai/otari#2245 ·
I maintainer di solito rispondono entro 1 giorno