feat: add logsSubscribe

This commit is contained in:
smypmsa
2025-03-18 16:03:46 +00:00
parent 669f8e8807
commit dacb3d377b
11 changed files with 617 additions and 23 deletions
+137
View File
@@ -0,0 +1,137 @@
"""
Test script to compare BlockListener and LogsListener
Runs both listeners simultaneously to compare their performance
"""
import asyncio
import logging
import os
import sys
import time
from pathlib import Path
sys.path.append(str(Path(__file__).parent.parent / "src"))
from core.pubkeys import PumpAddresses
from monitoring.block_listener import BlockListener
from monitoring.logs_listener import LogsListener
from trading.base import TokenInfo
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger("listener-comparison")
class TimingTokenCallback:
def __init__(self, name: str):
self.name = name
self.detected_tokens = []
self.detection_times = {}
async def on_token_created(self, token_info: TokenInfo) -> None:
"""Process detected token with timing information"""
token_key = str(token_info.mint)
detection_time = time.time()
self.detected_tokens.append(token_info)
self.detection_times[token_key] = detection_time
logger.info(f"[{self.name}] Detected: {token_info.name} ({token_info.symbol})")
print(f"\n{'=' * 50}")
print(f"[{self.name}] NEW TOKEN: {token_info.name}")
print(f"Symbol: {token_info.symbol}")
print(f"Mint: {token_info.mint}")
print(f"Detection time: {detection_time}")
print(f"{'=' * 50}\n")
async def run_comparison(test_duration: int = 300):
"""Run both listeners and compare their performance"""
wss_endpoint = os.environ.get("SOLANA_NODE_WSS_ENDPOINT")
if not wss_endpoint:
logger.error("SOLANA_NODE_WSS_ENDPOINT environment variable is not set")
return
logger.info(f"Connecting to WebSocket: {wss_endpoint}")
block_listener = BlockListener(wss_endpoint, PumpAddresses.PROGRAM)
logs_listener = LogsListener(wss_endpoint, PumpAddresses.PROGRAM)
block_callback = TimingTokenCallback("BlockListener")
logs_callback = TimingTokenCallback("LogsListener")
logger.info("Starting both listeners...")
block_task = asyncio.create_task(
block_listener.listen_for_tokens(block_callback.on_token_created)
)
logs_task = asyncio.create_task(
logs_listener.listen_for_tokens(logs_callback.on_token_created)
)
logger.info(f"Comparison running for {test_duration} seconds...")
try:
await asyncio.sleep(test_duration)
except KeyboardInterrupt:
logger.info("Test interrupted by user")
finally:
block_task.cancel()
logs_task.cancel()
try:
await asyncio.gather(block_task, logs_task, return_exceptions=True)
except asyncio.CancelledError:
pass
logger.info(f"BlockListener detected {len(block_callback.detected_tokens)} tokens")
logger.info(f"LogsListener detected {len(logs_callback.detected_tokens)} tokens")
# Find tokens detected by both listeners
block_mints = {str(token.mint) for token in block_callback.detected_tokens}
logs_mints = {str(token.mint) for token in logs_callback.detected_tokens}
common_mints = block_mints.intersection(logs_mints)
logger.info(f"Tokens detected by both listeners: {len(common_mints)}")
# Compare detection times for common tokens
if common_mints:
logger.info("\nPerformance comparison for tokens detected by both listeners:")
logger.info("Token Mint | BlockListener Time | LogsListener Time | Difference (ms)")
logger.info("-" * 80)
for mint in common_mints:
block_time = block_callback.detection_times.get(mint)
logs_time = logs_callback.detection_times.get(mint)
if block_time and logs_time:
diff_ms = abs(block_time - logs_time) * 1000 # Convert to milliseconds
faster = "BlockListener" if block_time < logs_time else "LogsListener"
logger.info(f"{mint[:10]}... | {block_time:.6f} | {logs_time:.6f} | {diff_ms:.2f}ms ({faster} faster)")
# Report tokens only detected by one listener
block_only = block_mints - logs_mints
logs_only = logs_mints - block_mints
if block_only:
logger.info(f"\nTokens only detected by BlockListener: {len(block_only)}")
for mint in block_only:
logger.info(f" - {mint}")
if logs_only:
logger.info(f"\nTokens only detected by LogsListener: {len(logs_only)}")
for mint in logs_only:
logger.info(f" - {mint}")
if __name__ == "__main__":
test_duration = 30 # seconds
if len(sys.argv) > 1:
try:
test_duration = int(sys.argv[1])
except ValueError:
logger.error(f"Invalid test duration: {sys.argv[1]}. Using default of {test_duration} seconds.")
logger.info("Starting listener comparison test")
logger.info(f"Will run for {test_duration} seconds")
asyncio.run(run_comparison(test_duration))
+97
View File
@@ -0,0 +1,97 @@
"""
Test script for BlockListener
Tests websocket monitoring for new pump.fun tokens using blockSubscribe
"""
import asyncio
import logging
import os
import sys
from pathlib import Path
sys.path.append(str(Path(__file__).parent.parent / "src"))
from core.pubkeys import PumpAddresses
from monitoring.block_listener import BlockListener
from trading.base import TokenInfo
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger("block-listener-test")
class TestTokenCallback:
def __init__(self):
self.detected_tokens = []
async def on_token_created(self, token_info: TokenInfo) -> None:
"""Process detected token"""
logger.info(f"New token detected: {token_info.name} ({token_info.symbol})")
logger.info(f"Mint: {token_info.mint}")
self.detected_tokens.append(token_info)
print(f"\n{'=' * 50}")
print(f"NEW TOKEN: {token_info.name}")
print(f"Symbol: {token_info.symbol}")
print(f"Mint: {token_info.mint}")
print(f"URI: {token_info.uri}")
print(f"Creator: {token_info.user}")
print(f"Bonding Curve: {token_info.bonding_curve}")
print(f"Associated Bonding Curve: {token_info.associated_bonding_curve}")
print(f"{'=' * 50}\n")
async def test_block_listener(
match_string: str | None = None,
creator_address: str | None = None,
test_duration: int = 60,
):
"""Test the block listener functionality"""
wss_endpoint = os.environ.get("SOLANA_NODE_WSS_ENDPOINT")
if not wss_endpoint:
logger.error("SOLANA_NODE_WSS_ENDPOINT environment variable is not set")
return []
logger.info(f"Connecting to WebSocket: {wss_endpoint}")
listener = BlockListener(wss_endpoint, PumpAddresses.PROGRAM)
callback = TestTokenCallback()
if match_string:
logger.info(f"Filtering tokens matching: {match_string}")
if creator_address:
logger.info(f"Filtering tokens by creator: {creator_address}")
listen_task = asyncio.create_task(
listener.listen_for_tokens(
callback.on_token_created,
match_string=match_string,
creator_address=creator_address,
)
)
logger.info(f"Listening for {test_duration} seconds...")
try:
await asyncio.sleep(test_duration)
except KeyboardInterrupt:
logger.info("Test interrupted by user")
finally:
listen_task.cancel()
try:
await listen_task
except asyncio.CancelledError:
pass
logger.info(f"Detected {len(callback.detected_tokens)} tokens")
for token in callback.detected_tokens:
logger.info(f" - {token.name} ({token.symbol}): {token.mint}")
return callback.detected_tokens
if __name__ == "__main__":
match_string = None # Update if you want to filter tokens by name/symbol
creator_address = None # Update if you want to filter tokens by creator address
test_duration = 15
logger.info("Starting block listener test (using blockSubscribe)")
asyncio.run(test_block_listener(match_string, creator_address, test_duration))
@@ -1,6 +1,6 @@
"""
Test script for PumpTokenListener
Tests websocket monitoring for new pump.fun tokens
Test script for LogsListener
Tests websocket monitoring for new pump.fun tokens using logsSubscribe
"""
import asyncio
@@ -12,13 +12,13 @@ from pathlib import Path
sys.path.append(str(Path(__file__).parent.parent / "src"))
from core.pubkeys import PumpAddresses
from monitoring.listener import PumpTokenListener
from monitoring.logs_listener import LogsListener
from trading.base import TokenInfo
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger("token-listener-test")
logger = logging.getLogger("logs-listener-test")
class TestTokenCallback:
@@ -41,16 +41,19 @@ class TestTokenCallback:
print(f"{'=' * 50}\n")
async def test_pump_token_listener(
async def test_logs_listener(
match_string: str | None = None,
creator_address: str | None = None,
test_duration: int = 60,
):
"""Test the token listener functionality"""
wss_endpoint = os.environ.get(
"SOLANA_NODE_WSS_ENDPOINT")
"""Test the logs listener functionality"""
wss_endpoint = os.environ.get("SOLANA_NODE_WSS_ENDPOINT")
if not wss_endpoint:
logger.error("SOLANA_NODE_WSS_ENDPOINT environment variable is not set")
return []
logger.info(f"Connecting to WebSocket: {wss_endpoint}")
listener = PumpTokenListener(wss_endpoint, PumpAddresses.PROGRAM)
listener = LogsListener(wss_endpoint, PumpAddresses.PROGRAM)
callback = TestTokenCallback()
if match_string:
@@ -90,5 +93,5 @@ if __name__ == "__main__":
creator_address = None # Update if you want to filter tokens by creator address
test_duration = 15
logger.info("Starting token listener test")
asyncio.run(test_pump_token_listener(match_string, creator_address, test_duration))
logger.info("Starting logs listener test (using logsSubscribe)")
asyncio.run(test_logs_listener(match_string, creator_address, test_duration))