- 区块链
- 后端
【免费下载链接】chia-blockchain
Chia blockchain python implementation (full node, farmer, harvester, timelord, and wallet)
导读
本文聚焦 Chia 区块链 Python 实现中的chia/solver/服务模块:它是 V2 图(v2 plot)部分证明(partial proof)求解的专用服务边界,负责接收 Farmer 发来的SolverInfo消息,通过 Rust 扩展chia_rs.solve_proof()将PartialProof片段展开为完整证明字节,并返回SolverResponse供 Farmer 重新接入常规的时空证明(proof-of-space)处理流程。读完本文,你将掌握 solver 服务的职责边界、端到端运行时流程、SolverInfo/SolverResponse网络协议契约、config.yaml中的完整配置项、可信对等节点准入机制,以及 Farmer 侧请求关联与响应处理的关键实现。
Solver 是 Chia 网络中一个刻意保持"小而专"的服务:它不是链、图、密钥或 Farmer 状态的权威,只负责把证明展开这种计算密集工作从 Farmer 热路径中分离出来。
为什么需要 Solver:V2 图与部分证明的职责分离
V1 图由 Harvester 直接生成完整证明并上报 Farmer;而 V2 图采用不同的架构:Harvester 在本地只做质量查找(quality lookup),产出部分证明(partial proof)并发送给 Farmer,由独立的 Solver 服务完成昂贵的证明展开。
从源码结构看,这一设计体现了清晰的关注点分离:
| 职责 | 归属模块 |
|---|---|
| 图文件与证明器(prover)的本地所有权 | Harvester(chia/harvester/) |
| 签名点上下文校验、Harvester 关联、请求广播与响应重建 | Farmer(chia/farmer/) |
| 昂贵的证明展开(partial → full proof) | Solver(chia/solver/+chia_rs) |
| 最终证明的验收 | Full node 与共识层 |
Solver 自身不具备图的打开能力,也不验证图归属。V2 Harvester 只提供部分证明加图元数据,V1 图则完全绕过 Solver 直接返回完整证明(见 harvester_api.py 中_handle_v1_responses与_handle_v2_responses的并行处理逻辑)。
正因如此,Solver 吞吐量与响应处理是 Farmer 的热路径(hot path)——尽管 Solver 服务本身实现很小,任何一个响应延迟都会直接影响 Farmer 对证明的后续处理。
主运行时流程:从部分证明到完整证明的端到端链路
依据 farmer_api.py 与 solver_api.py 的实现,完整流程如下:
- Harvester 产出部分证明:V2 Harvester 对签名点找到合格的部分证明后,封装为
PartialProofsData(包含challenge_hash、sp_hash、plot_identifier、partial_proofs、signage_point_index、plot_size、plot_index、meta_group、strength等)发送给 Farmer。 - Farmer 校验签名点上下文:Farmer 收到
partial_proofs消息后,若sp_hash不在其短时签名点缓存(farmer.number_of_responses)中则拒绝处理;新签名点会登记到cache_add_time。 - Farmer 登记待处理请求:对每个部分证明,Farmer 以
bytes(partial_proof)为键,将原始PartialProofsData与来源 Harvester peer 存入pending_solver_requests(见 farmer.py 第 208 行的pending_solver_requests: dict[bytes, dict[str, Any]])。 - Farmer 广播 solve 请求:构造
SolverInfo(partial_proof, plot_id, strength, size),通过send_to_all([msg], NodeType.SOLVER)广播给所有当前 Solver 连接(farmer_api.py的partial_proofs处理器)。 - Solver 求解:收到
solve后检查solver.started,调用chia_rs.solve_proof(partial_proof, plot_id, strength, size, constants.TESTNET),成功则返回SolverResponse(partial_proof, proof)。 - Farmer 重建并继续:Farmer 的
solution_response处理器仅当partial_proof匹配待处理请求时才接受;空证明直接丢弃;随后用求解得到的 proof 字节重建 V2ProofOfSpace,封装为NewProofOfSpace并调用new_proof_of_space()(携带原始 Harvester peer 继续后续签名流程)。
关键实现细节(farmer_api.pysolution_response,第 572–629 行):
- 关联键是序列化后的部分证明本身(
key = bytes(response.partial_proof)),不是 WebSocket 请求 ID; - 重建的
ProofOfSpace中size字段固定为uint8(0)(V2 证明中 size 不使用),size field的语义与 V1 不同; plot_identifier由partial_proof.get_string(strength).hex() + plot_identifier拼接而来;- 最终通过
await self.new_proof_of_space(new_proof_of_space, original_peer)重新进入常规证明处理。
关联键的脆弱性:请求关联键仅为序列化部分证明。如果不同 Harvester/签名点上下文并发出现完全相同的部分证明,后写入的请求会覆盖先前的元数据。修改这一键控逻辑属于 Farmer/Solver 正确性敏感改动。
网络与协议契约:SolverInfo / SolverResponse
消息定义
Solver 的线上契约定义在 solver_protocol.py,两者都是基于chia.util.streamable的Streamable冻结数据类:
@streamable @dataclass(frozen=True) class SolverInfo(Streamable): partial_proof: PartialProof # 来自 chia_rs 的部分证明片段 plot_id: bytes32 # 图 ID strength: uint8 # V2 强度参数 size: uint8 # k-size @streamable @dataclass(frozen=True) class SolverResponse(Streamable): partial_proof: PartialProof # 回传原部分证明,供 Farmer 关联匹配 proof: bytes # 展开后的完整证明字节消息类型与发送授权
ProtocolMessageTypes.solve = 109,solution_response = 108(见 protocol_message_types.py 第 142、145 行);- 发送授权不对称:Farmer 可以发送
solve,Solver 可以发送solution_response; SolverAPI.solve()虽通过@metadata.request(peer_required=False, reply_types=[ProtocolMessageTypes.solution_response])声明了回复类型,但 Farmer 实际通过广播发送solve而非 request-id 的call_api()匹配。这意味着 Solver 的响应是作为入站协议消息处理的,而非请求 ID 状态机匹配(见 solver_api.py 第 32 行)。
协议版本与能力
NodeType.SOLVER拥有独立的协议版本:"0.0.37"(见 shared_protocol.py 第 19 行),并挂载与其它节点类型相同的共享能力集;solve与solution_response被期望保持为小型、受速率限制(rate-limited)的载荷。不要向这两个 schema 添加大字段,否则必须同步更新chia/protocols/与chia/server/中的速率限制假设;- Schema 修改遵循协议锁步(protocol lockstep)流程:消息类型、发送者映射、API/stub 元数据、速率限制、兼容性测试以及协议版本号都需要一并评估。
生命周期、配置与对等节点准入
服务组装
start_solver.py 的create_solver_service()(第 33–70 行)遵循 Chia 标准服务组装模式:
- 读取
config["solver"]段配置与selected_network; - 基于
DEFAULT_CONSTANTS应用网络覆盖(update_testnet_overrides)并替换字符串常量为字节(replace_str_to_bytes); - 构建
Solver节点、SolverAPI对等 API,若start_rpc_server为真则挂载SolverRpcApi与rpc_port; - 以
NodeType.SOLVER类型、advertised_port=service_config["port"]包装为Service(SolverService = Service[Solver, SolverAPI, SolverRpcApi],见 solver_service.py)。
完整配置项(config.yaml 的 solver 段)
以下配置来自 initial-config.yaml 第 667–701 行,是chia init后config.yaml中 solver 段的模板:
solver: # Solver 服务监听端口 port: 8666 # 是否启用 UPnP 端口转发 enable_upnp: False # 可信 solver 对等节点 Node ID,默认仅这些节点可连接 trusted_peers: 0ThisisanexampleNodeID7ff9d60f1c3fa270c213c0ad0cb89c01274634a7c3cb7: Does_not_matter # False:接受所有对等节点连接 # True(默认):仅接受 localhost 与 trusted_peers 中的连接 trusted_peers_only: True logging: *logging network_overrides: *network_overrides selected_network: *selected_network # Solver 求解线程池大小 num_threads: 1 # 本地 RPC 服务配置(仅观测用途) rpc_port: 8667 start_rpc_server: True ssl: private_crt: "config/ssl/solver/private_solver.crt" private_key: "config/ssl/solver/private_solver.key" public_crt: "config/ssl/solver/public_solver.crt" public_key: "config/ssl/solver/public_solver.key"Farmer 侧对接配置
Farmer 段中的solver_peers指定要连接的 solver 列表(initial-config.yaml 第 215–218 行):
farmer: # The farmer will attempt to connect to these solvers for V2 plot solving solver_peers: - host: *self_hostname # 默认本机 port: 8666 # 与 solver.port 对应可信对等节点准入实现
Solver.on_connect()(solver.py 第 81–91 行)实现准入逻辑:
- 若连接来自
trusted_peers配置中的节点 ID,直接接受; - 否则若
trusted_peers_only为False(即被显式禁用),接受并记录日志; - 否则记录警告并关闭连接。
线程池与关闭语义
num_threads控制ThreadPoolExecutor大小(线程名前缀solver-)。注意:当前solve()实现是在 API 处理器中同步调用solve_proof(),并未把工作调度到执行器上(见 solver.py 第 70–76 行与 solver_api.py 第 48 行)——因此调整求解吞吐或阻塞行为时,必须评估 API 任务延迟与事件循环影响;- 关闭流程:
manage()设置_shut_down = True、标记服务关闭,并以executor.shutdown(wait=True)等待线程池任务排空(solver.py 第 57–68 行)。
本地 RPC:仅观测
SolverRpcApi(solver_rpc_api.py)只暴露一个路由get_state,返回{"started": self.service.started}。它不配置对等节点、不提交求解工作、不暴露证明数据;_state_changed()返回空列表,即不产生任何 WebSocket 事件——UI/守护进程应将其视为仅轮询(polling-only)接口。
Farmer 侧请求关联与connect_to_solver
广播与响应匹配
Farmer 对每个部分证明广播solve给所有当前 Solver 连接,并在solution_response中按bytes(partial_proof)查找待处理请求:
- 未命中则记录 "unknown partial proof" 警告并丢弃;
- 命中则弹出请求,取出原始
proof_data与original_peer; - 空 proof(
len(proof_bytes) == 0)记录警告后返回,不继续处理; - 成功则重建
NewProofOfSpace并调用new_proof_of_space()。
由于 Farmer 广播给所有 Solver,多个 Solver 可能竞争回答同一个部分证明:第一个匹配的响应会弹出待处理请求,之后到达的合法响应会被记录为未知并丢弃(farmer_api.py 第 572–629 行)。
请求清理
SolverAPI.solve()返回None时(如求解失败或服务未启动)会对 Farmer静默无响应。Farmer 侧的待处理请求只在发送失败或收到匹配响应时清理;无响应场景下条目会一直留存,直到周边 Farmer 缓存清理任务(_periodically_clear_cache_and_refresh_task,基于SUB_SLOT_TIME_TARGET * 3的超时清理,见 farmer.py 第 936–968 行)处理相关状态。
connect_to_solver RPC
Farmer RPC 暴露/connect_to_solver路由(farmer_rpc_api.py 第 109、372 行起):先关闭所有现有NodeType.SOLVER连接,再解析目标host/port发起新连接,用于动态切换/重连 solver。CLI 侧入口位于 farm_funcs.py(chia farm ...相关命令调用farmer_client.connect_to_solver(host, port))。对应集成测试见 test_farmer_harvester_rpc.py 的test_farmer_connect_to_solver(第 528–553 行),覆盖成功连接现有 solver 与连接不存在 solver(localhost:65000)抛ResponseFailureError两种场景。
关键脆弱点(Fragility Hotspots)
constants.TESTNET传入solve_proof():网络/分叉行为发生变化时,需确认该标志是否是 mainnet 与 testnet 配置下 Rust API 的预期输入(solver.py 第 73 行)。- 日志热路径:Solver 会记录部分证明片段与 plot ID(
partial_proof.fragments[:5]、plot-id)。应避免在热签名点路径上提高日志量或引入敏感本地元数据。 - 无响应语义:
SolverAPI.solve()返回None时对 Farmer 静默无响应,待处理请求的清理依赖发送失败或匹配响应,长期无响应可能残留条目直至周边缓存清理。 - 多 Solver 竞争:广播语义下多个 Solver 可能竞答同一部分证明,首个匹配响应弹出请求,后续响应被丢弃。
- RPC 无事件推送:
SolverRpcApi._state_changed()不返回 WebSocket 事件,除非刻意增加事件支持,否则 UI/守护进程只能轮询。
测试策略
从文档规划与仓库测试现状看,Solver 相关测试应覆盖以下层次:
- 单元/服务测试:就绪门控(
ready()依赖solver.started)、成功构造SolverResponse、solve_proof()失败时返回无消息、服务关闭时执行器资源正确排空; - Farmer/Solver 集成测试:待处理请求插入、未知响应丢弃、空证明清理、成功重建
NewProofOfSpace、Solver 发送异常、单个部分证明的多个 Solver 响应。仓库中已具备的集成示例是test_farmer_connect_to_solver(fixturefarmer_one_harvester_solver,见 test_farmer_harvester_rpc.py); - 协议测试:Solver 消息序列化,以及 schema/消息 ID 变更时发送者映射与回复元数据的静态不变量;
- 生命周期/RPC 测试:默认与配置的 solver peer 连接、可信对等节点准入、
get_state、通过 farmerconnect_to_solver的重连行为。
源码指路
- Solver 服务/API/RPC: solver.py、solver_api.py、solver_rpc_api.py、start_solver.py、solver_service.py
- Farmer 侧请求关联: farmer.py、farmer_api.py、farmer_rpc_api.py
- Harvester 部分证明产出: harvester_api.py、prover.py
- 线上契约与发送授权: solver_protocol.py、protocol_message_types.py、shared_protocol.py
- 证明展开实现边界:
chia_rs.solve_proof(Rust 扩展,Python 侧仅做编排与边界封装) - 配置模板: initial-config.yaml(solver 段第 667–701 行,farmer
solver_peers第 215–218 行)
综上,Solver 模块是 Chia V2 图架构中"计算下放"的关键一环:职责边界清晰、协议精简、配置集中在config.yaml的solver段,而其正确性与性能高度依赖 Farmer 侧的请求关联、广播竞答处理与缓存清理语义。理解这一条链路,是排障 V2 图出块延迟与证明丢失问题的起点。
- 区块链
- 后端
【免费下载链接】chia-blockchain
Chia blockchain python implementation (full node, farmer, harvester, timelord, and wallet)
相关推荐
Chia 节点服务 API 协议元数据解析:chia/apis 存根模块与 ApiMetadata 装饰器运行机制
Chia 节点服务 API 协议元数据解析:chia/apis 存根模块与 ApiMetadata 装饰器运行机制 导读 chia/apis/ 目录是 Chia
区块链后端Devenv 声明式配置 PostgreSQL 服务:services.postgres 模块配置与源码级解析
Devenv 声明式配置 PostgreSQL 服务:services.postgres 模块配置与源码级解析 devenv 通过 services.postg
开发工具CLIProxySQL DuckDB 服务器插件:嵌入分析引擎、双协议监听与配置运维全解析
ProxySQL DuckDB 服务器插件:嵌入分析引擎、双协议监听与配置运维全解析 ProxySQL 的 DuckDB Server Plugin 将 Duc
后端数据库负载均衡
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考