Skip to content

Commit fb400e7

Browse files
committed
Adds a command to compare latencies of given connections to help the user pick the fastest for their region.
1 parent 2e6a7ef commit fb400e7

File tree

3 files changed

+87
-7
lines changed

3 files changed

+87
-7
lines changed

bittensor_cli/cli.py

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@
4242
from bittensor_cli.src.bittensor import utils
4343
from bittensor_cli.src.bittensor.balances import Balance
4444
from bittensor_cli.src.bittensor.chain_data import SubnetHyperparameters
45-
from bittensor_cli.src.bittensor.subtensor_interface import SubtensorInterface
45+
from bittensor_cli.src.bittensor.subtensor_interface import (
46+
SubtensorInterface,
47+
best_connection,
48+
)
4649
from bittensor_cli.src.bittensor.utils import (
4750
console,
4851
err_console,
@@ -1048,6 +1051,9 @@ def __init__(self):
10481051
"remove", rich_help_panel=HELP_PANELS["LIQUIDITY"]["LIQUIDITY_MGMT"]
10491052
)(self.liquidity_remove)
10501053

1054+
# utils app
1055+
self.utils_app.command("latency")(self.best_connection)
1056+
10511057
def generate_command_tree(self) -> Tree:
10521058
"""
10531059
Generates a rich.Tree of the commands, subcommands, and groups of this app
@@ -6326,6 +6332,57 @@ def convert(
63266332
f"{Balance.from_tao(tao).rao}{Balance.rao_unit}",
63276333
)
63286334

6335+
def best_connection(
6336+
self,
6337+
additional_networks: Optional[list[str]] = typer.Option(
6338+
None,
6339+
"--network",
6340+
help="Network(s) to test for the best connection",
6341+
),
6342+
):
6343+
f"""
6344+
This command will give you the latency of all finney-like network in additional to any additional networks you specify via the {arg__("--network")} flag
6345+
6346+
The results are two-fold. One column is the overall time to initialise a connection, send a request, and wait for the result. The second column measures single ping-pong speed once connected.
6347+
6348+
EXAMPLE
6349+
6350+
[green]$[/green] btcli utils latency --network ws://189.234.12.45 --network wss://mysubtensor.duckdns.org
6351+
6352+
"""
6353+
additional_networks = additional_networks or []
6354+
if any(not x.startswith("ws") for x in additional_networks):
6355+
err_console.print(
6356+
"Invalid network endpoint. Ensure you are specifying a valid websocket endpoint.",
6357+
)
6358+
return False
6359+
results: dict[str, list[float]] = self._run_command(
6360+
best_connection(Constants.finney_nodes + (additional_networks or []))
6361+
)
6362+
sorted_results = {
6363+
k: v for k, v in sorted(results.items(), key=lambda item: item[1][0])
6364+
}
6365+
table = Table(
6366+
Column("Network"),
6367+
Column("End to End Latency", style="cyan"),
6368+
Column("Single Request Ping", style="cyan"),
6369+
title="Connection Latencies (seconds)",
6370+
caption="lower value is faster",
6371+
)
6372+
for n_name, (overall_latency, single_request) in sorted_results.items():
6373+
table.add_row(n_name, str(overall_latency), str(single_request))
6374+
console.print(table)
6375+
fastest = next(iter(sorted_results.keys()))
6376+
if conf_net := self.config.get("network", ""):
6377+
if not conf_net.startswith("ws") and conf_net in Constants.networks:
6378+
conf_net = Constants.network_map[conf_net]
6379+
if conf_net != fastest:
6380+
console.print(
6381+
f"The fastest network is {fastest}. You currently have {conf_net} selected as your default network."
6382+
f"\nYou can update this with {arg__(f'btcli config set --network {fastest}')}"
6383+
)
6384+
return True
6385+
63296386
def run(self):
63306387
self.app()
63316388

bittensor_cli/src/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class Constants:
2323
dev_entrypoint = "wss://dev.chain.opentensor.ai:443"
2424
local_entrypoint = "ws://127.0.0.1:9944"
2525
latent_lite_entrypoint = "wss://lite.sub.latent.to:443"
26+
finney_nodes = [finney_entrypoint, subvortex_entrypoint, latent_lite_entrypoint]
2627
network_map = {
2728
"finney": finney_entrypoint,
2829
"test": finney_test_entrypoint,

bittensor_cli/src/bittensor/subtensor_interface.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
import asyncio
22
import os
3+
import time
34
from typing import Optional, Any, Union, TypedDict, Iterable
45

56
import aiohttp
7+
from async_substrate_interface.async_substrate import (
8+
DiskCachedAsyncSubstrateInterface,
9+
AsyncSubstrateInterface,
10+
)
11+
from async_substrate_interface.errors import SubstrateRequestException
612
from async_substrate_interface.utils.storage import StorageKey
713
from bittensor_wallet import Wallet
814
from bittensor_wallet.bittensor_wallet import Keypair
915
from bittensor_wallet.utils import SS58_FORMAT
1016
from scalecodec import GenericCall
11-
from async_substrate_interface.errors import SubstrateRequestException
1217
import typer
18+
import websockets
1319

14-
15-
from async_substrate_interface.async_substrate import (
16-
DiskCachedAsyncSubstrateInterface,
17-
AsyncSubstrateInterface,
18-
)
1920
from bittensor_cli.src.bittensor.chain_data import (
2021
DelegateInfo,
2122
StakeInfo,
@@ -1654,3 +1655,24 @@ async def get_subnet_prices(
16541655
map_[netuid_] = Balance.from_rao(int(current_price * 1e9))
16551656

16561657
return map_
1658+
1659+
1660+
async def best_connection(networks: list[str]):
1661+
"""
1662+
Basic function to compare the latency of a given list of websocket endpoints
1663+
Args:
1664+
networks: list of network URIs
1665+
1666+
Returns:
1667+
{network_name: [end_to_end_latency, single_request_latency]}
1668+
1669+
"""
1670+
results = {n: [0.0, 0.0] for n in networks}
1671+
for network in networks:
1672+
t1 = time.monotonic()
1673+
async with websockets.connect(network) as websocket:
1674+
pong = await websocket.ping()
1675+
latency = await pong
1676+
t2 = time.monotonic()
1677+
results[network] = [t2 - t1, latency]
1678+
return results

0 commit comments

Comments
 (0)