Skip to content

Commit 36f7c64

Browse files
committed
connect to solver cli
1 parent 51078a9 commit 36f7c64

File tree

8 files changed

+107
-10
lines changed

8 files changed

+107
-10
lines changed

chia/cmds/configure.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def configure(
3636
crawler_minimum_version_count: Optional[int],
3737
seeder_domain_name: str,
3838
seeder_nameserver: str,
39+
set_solver_trusted_peers_only: str,
3940
) -> None:
4041
config_yaml = "config.yaml"
4142
with lock_and_load_config(root_path, config_yaml, fill_missing_services=True) as config:
@@ -63,11 +64,19 @@ def configure(
6364
if set_solver_peer:
6465
try:
6566
host, port = parse_host_port(set_solver_peer)
67+
# Set single solver peer (overrides any existing)
6668
config["farmer"]["solver_peers"] = [{"host": host, "port": port}]
67-
print("Solver peer updated for farmer")
69+
print(f"Solver peer updated to {host}:{port}")
6870
change_made = True
6971
except ValueError:
7072
print("Solver address must be in format [IP:Port]")
73+
if set_solver_trusted_peers_only:
74+
config["solver"]["trusted_peers_only"] = str2bool(set_solver_trusted_peers_only)
75+
if str2bool(set_solver_trusted_peers_only):
76+
print("Solver will only accept trusted peer connections")
77+
else:
78+
print("Solver will accept connections from all peers")
79+
change_made = True
7180
if set_fullnode_port:
7281
config["full_node"]["port"] = int(set_fullnode_port)
7382
config["full_node"]["introducer_peer"]["port"] = int(set_fullnode_port)
@@ -247,6 +256,11 @@ def configure(
247256
@click.option("--set-node-introducer", help="Set the introducer for node - IP:Port", type=str)
248257
@click.option("--set-farmer-peer", help="Set the farmer peer for harvester - IP:Port", type=str)
249258
@click.option("--set-solver-peer", help="Set the solver peer for farmer - IP:Port", type=str)
259+
@click.option(
260+
"--set-solver-trusted-peers-only",
261+
help="Enable/disable trusted peer requirement for solver connections",
262+
type=click.Choice(["true", "t", "false", "f"]),
263+
)
250264
@click.option(
251265
"--set-fullnode-port",
252266
help="Set the port to use for the fullnode, useful for testing",
@@ -316,6 +330,7 @@ def configure_cmd(
316330
crawler_minimum_version_count: int,
317331
seeder_domain_name: str,
318332
seeder_nameserver: str,
333+
set_solver_trusted_peers_only: str,
319334
) -> None:
320335
configure(
321336
ChiaCliContext.set_default(ctx).root_path,
@@ -334,4 +349,5 @@ def configure_cmd(
334349
crawler_minimum_version_count,
335350
seeder_domain_name,
336351
seeder_nameserver,
352+
set_solver_trusted_peers_only,
337353
)

chia/cmds/farm.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,26 @@ def challenges_cmd(ctx: click.Context, farmer_rpc_port: Optional[int], limit: in
105105
from chia.cmds.farm_funcs import challenges
106106

107107
asyncio.run(challenges(ChiaCliContext.set_default(ctx).root_path, farmer_rpc_port, limit))
108+
109+
110+
@farm_cmd.command("connect-solver", help="Connect to a solver")
111+
@click.option(
112+
"-fp",
113+
"--farmer-rpc-port",
114+
help="Set the port where the Farmer is hosting the RPC interface",
115+
type=int,
116+
default=None,
117+
show_default=True,
118+
)
119+
@click.argument("solver_address", required=True)
120+
@click.pass_context
121+
def connect_solver_cmd(
122+
ctx: click.Context,
123+
farmer_rpc_port: Optional[int],
124+
solver_address: str,
125+
) -> None:
126+
import asyncio
127+
128+
from chia.cmds.farm_funcs import solver_connect
129+
130+
asyncio.run(solver_connect(ChiaCliContext.set_default(ctx).root_path, farmer_rpc_port, solver_address))

chia/cmds/farm_funcs.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from chia.cmds.units import units
1212
from chia.farmer.farmer_rpc_client import FarmerRpcClient
1313
from chia.full_node.full_node_rpc_client import FullNodeRpcClient
14+
from chia.util.config import lock_and_load_config, save_config
1415
from chia.util.errors import CliRpcConnectionError
1516
from chia.util.network import is_localhost
1617
from chia.wallet.wallet_rpc_client import WalletRpcClient
@@ -217,3 +218,33 @@ def process_harvesters(harvester_peers_in: dict[str, dict[str, Any]]) -> None:
217218
print("For details on farmed rewards and fees you should run 'chia wallet show'")
218219
else:
219220
print("Note: log into your key using 'chia wallet show' to see rewards for each key")
221+
222+
223+
async def solver_connect(root_path: Path, farmer_rpc_port: Optional[int], solver_address: str) -> None:
224+
from chia.util.network import parse_host_port
225+
226+
try:
227+
host, port = parse_host_port(solver_address)
228+
except ValueError:
229+
print("Solver address must be in format [IP:Port]")
230+
return
231+
try:
232+
with lock_and_load_config(root_path, "config.yaml") as config:
233+
config["farmer"]["solver_peers"] = [{"host": host, "port": port}]
234+
save_config(root_path, "config.yaml", config)
235+
print(f"✓ Updated config with solver peer {host}:{port}")
236+
except Exception as e:
237+
print(f"✗ Failed to update config: {e}")
238+
return
239+
try:
240+
async with get_any_service_client(FarmerRpcClient, root_path, farmer_rpc_port) as (farmer_client, _):
241+
result = await farmer_client.connect_to_solver(host, port)
242+
if result.get("success"):
243+
print(f"✓ Connected to solver at {host}:{port}")
244+
else:
245+
error = result.get("error", "Unknown error")
246+
print(f"✗ Failed to connect to solver: {error}")
247+
except CliRpcConnectionError:
248+
print("✗ Could not connect to farmer. Make sure farmer is running.")
249+
except Exception as e:
250+
print(f"✗ Error connecting to solver: {e}")

chia/cmds/init_funcs.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ def chia_init(
299299
seeder_domain_name="",
300300
seeder_nameserver="",
301301
set_solver_peer="",
302+
set_solver_trusted_peers_only="",
302303
)
303304
if fix_ssl_permissions:
304305
fix_ssl(root_path)
@@ -326,6 +327,7 @@ def chia_init(
326327
seeder_domain_name="",
327328
seeder_nameserver="",
328329
set_solver_peer="",
330+
set_solver_trusted_peers_only="",
329331
)
330332
create_all_ssl(root_path)
331333
if fix_ssl_permissions:

chia/farmer/farmer_rpc_api.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
from chia.farmer.farmer import Farmer
1212
from chia.plot_sync.receiver import Receiver
1313
from chia.protocols.harvester_protocol import Plot
14+
from chia.protocols.outbound_message import NodeType
1415
from chia.rpc.rpc_server import Endpoint, EndpointResult
16+
from chia.types.peer_info import PeerInfo
17+
from chia.util.network import resolve
1518
from chia.util.paginator import Paginator
1619
from chia.util.streamable import Streamable, streamable
1720
from chia.util.ws_message import WsRpcMessage, create_payload_dict
@@ -102,6 +105,7 @@ def get_routes(self) -> dict[str, Endpoint]:
102105
"/get_harvester_plots_keys_missing": self.get_harvester_plots_keys_missing,
103106
"/get_harvester_plots_duplicates": self.get_harvester_plots_duplicates,
104107
"/get_pool_login_link": self.get_pool_login_link,
108+
"/connect_to_solver": self.connect_to_solver,
105109
}
106110

107111
async def _state_changed(self, change: str, change_data: Optional[dict[str, Any]]) -> list[WsRpcMessage]:
@@ -363,3 +367,19 @@ async def get_pool_login_link(self, request: dict[str, Any]) -> EndpointResult:
363367
if login_link is None:
364368
raise ValueError(f"Failed to generate login link for {launcher_id.hex()}")
365369
return {"login_link": login_link}
370+
371+
async def connect_to_solver(self, request: dict[str, Any]) -> EndpointResult:
372+
for connection in self.service.server.get_connections(NodeType.SOLVER):
373+
host = connection.peer_info.host
374+
port = connection.peer_server_port
375+
await connection.close()
376+
self.service.log.info(f"Disconnected from solver at {host}:{port}")
377+
host = request["host"]
378+
port = request["port"]
379+
target_node = PeerInfo(await resolve(host), port)
380+
on_connect = getattr(self.service, "on_connect", None)
381+
if await self.service.server.start_client(target_node, on_connect):
382+
self.service.log.info(f"Connected to solver at {host}:{port}")
383+
return {"success": True}
384+
else:
385+
return {"success": False, "error": f"Could not connect to solver at {host}:{port}"}

chia/farmer/farmer_rpc_client.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,7 @@ async def get_pool_login_link(self, launcher_id: bytes32) -> Optional[str]:
8585
return cast(Optional[str], result["login_link"])
8686
except ValueError: # not connected to pool.
8787
return None
88+
89+
async def connect_to_solver(self, host: str, port: int) -> dict[str, Any]:
90+
"""Connect farmer to specific solver"""
91+
return await self.fetch("connect_to_solver", {"host": host, "port": port})

chia/solver/solver.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
from chia.rpc.rpc_server import StateChangedProtocol, default_get_connections
1515
from chia.server.server import ChiaServer
1616
from chia.server.ws_connection import WSChiaConnection
17-
from chia.util.network import is_localhost
1817

1918
log = logging.getLogger(__name__)
2019

@@ -76,15 +75,13 @@ def get_connections(self, request_node_type: Optional[NodeType]) -> list[dict[st
7675
return default_get_connections(server=self.server, request_node_type=request_node_type)
7776

7877
async def on_connect(self, connection: WSChiaConnection) -> None:
79-
if is_localhost(connection.peer_info.host):
80-
self.log.info(f"Accepting localhost connection from {connection.connection_type}: {connection.get_peer_logging()}")
78+
if not self.config.get("trusted_peers_only", True):
79+
self.log.info(f"trusted peers check disabled, Accepting connection from {connection.get_peer_logging()}")
8180
return
82-
83-
trusted_peers = self.config.get("trusted_peers", {})
84-
if self.server.is_trusted_peer(connection, trusted_peers):
85-
self.log.info(f"Accepting trusted peer connection from {connection.connection_type}: {connection.get_peer_logging()}")
81+
if self.server.is_trusted_peer(connection, self.config.get("trusted_peers", {})):
82+
self.log.info(f"Accepting connection from {connection.get_peer_logging()}")
8683
return
87-
self.log.warning(f"Rejecting untrusted connection from {connection.connection_type}: {connection.get_peer_logging()}")
84+
self.log.warning(f"Rejecting untrusted connection from {connection.get_peer_logging()}")
8885
await connection.close()
8986

9087
async def on_disconnect(self, connection: WSChiaConnection) -> None:

chia/util/initial-config.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,11 @@ solver:
643643

644644
# Node IDs of trusted solver peers, only these can connect by default
645645
trusted_peers:
646-
0ThisisanexampleNodeID7ff9d60f1c3fa270c213c0ad0cb89c01274634a7c3cb7: Does_not_matter
646+
localhost: 9999
647+
648+
# If False, accepts connections from all peers (not just trusted_peers)
649+
# If True (default), only accepts localhost and trusted_peers connections
650+
trusted_peers_only: True
647651

648652
# Logging configuration
649653
logging: *logging

0 commit comments

Comments
 (0)