这是一个设计/audit 备忘,不是 bug 报告。它与 #320 有背景关联,但不是同一个议题。
背景
在常见拓扑中,bootstrap/address-book 节点主要负责 peer 引导和发现入口;fullnode/producer 节点才实际持有 group block/data,并可作为同步数据提供方。
本地联调中观察到一个值得记录的现象:fullnode 加入 group 后,如果自动发现或初始连接阶段只连接到了 bootstrap/address-book 节点,而尚未发现或连接到 group owner/fullnode,syncer 可能无法从合适的数据提供方同步。bootstrap 节点通常不承担 group block/data provider 职责,也不一定支持 Rex 协议;当后续两个 fullnode 显式互连后,syncer 可以正常从 owner/fullnode 同步到目标 block 和内容。
这说明问题重点不在于 bootstrap 是否应该承担数据同步职责,而在于 fullnode/syncer 选择 Rex provider 时需要更明确的 peer 能力、group 角色和数据可用性过滤。
当前源码链路
当前 Rex 请求链路大致如下:
RexSyncer.syncBlockTaskSender() 构造 REQ_BLOCK 请求,并调用 ConnMgr.SendReqTrxRex()。
ConnMgr.SendReqTrxRex() 从 group user topic 获取 psconn.Topic.ListPeers()。
RexService.Publish() 优先使用传入的 channelpeers;如果 channelpeers 为空,则回退到 Host.Network().Peers()。
RumGroupPeerStore.filterPeers() 会过滤 bad response peers,并基于 block provider scorer / capacity 做排序与裁剪。
PublishToPeerId() 对候选 peer 创建 Rex stream;如果 peer 不支持 Rex 协议或连接失败,会计入 bad response。
因此,问题更准确地说不是“DHT 结果直接进入 Rex provider 列表”,而是:DHT/bootstrap/manual/pubsub peer exchange 发现并连接的 peer 会间接影响 pubsub topic peers;当 topic peers 为空时,当前逻辑还可能回退到所有 connected peers。这样会让 bootstrap/address-book-only peer 或不具备目标 group 数据能力的 peer 成为 Rex 请求候选,导致无效请求、重试等待和同步收敛变慢。
现状缺口
bootstrap/address-book peer 与 group data provider peer 的角色边界不够显式。
syncer provider 选择目前主要依赖 topic peers、connected peers fallback 和历史评分,不够依赖协议能力、group membership 和数据可用性。
topic peers 为空时回退到所有 connected peers,对 group sync 来说风险较高,容易把非 group data provider 当作候选。
Rex 请求前缺少明确的协议能力过滤:例如 peer 是否支持当前 network 的 /quorum/<network>/rex/2.0.0。
peer 元数据/握手能力不足时,syncer 难以在发起 Rex 请求前判断:peer role、目标 group membership、latest block height、是否可提供目标 group chain data。
现有 scorer 框架已经存在,但更偏历史响应质量;它不能替代发请求前的硬性能力过滤。
provider 选择失败、协议不匹配、group 不匹配、无可用 group peer 等情况还需要更结构化的日志和指标,便于区分“网络未发现 peer”和“发现 peer 但不可提供数据”。
成熟实施方案建议
P0:限制 group sync 的候选来源
目标:先避免把明显不合适的 peer 当作 Rex provider。
对 group Rex sync,优先只使用 group user topic peers 或显式 trusted group peers。
topic peers 为空时,不要默认回退到所有 connected peers;至少应通过配置控制该 fallback,生产默认关闭。
如果没有可用 group peers,返回或记录明确错误,例如 ErrNoGroupPeersAvailable,而不是对任意 connected peer 发 Rex 请求。
bootstrap/address-book-only peer 默认不进入 group data provider candidate set。
P1:Rex 请求前做协议能力过滤
目标:在创建 Rex stream 之前过滤掉确定不支持 Rex 的 peer。
通过 libp2p identify / peerstore / protocol list 缓存 peer 支持的协议。
只向支持当前 Rex protocol id 的 peer 发起 Rex 请求。
对能力未知的 peer,可做一次轻量探测并缓存结果。
协议不匹配应计入结构化原因,而不是只表现为普通 stream negotiation failure。
P2:引入 group provider metadata
目标:让 syncer 能区分“网络层可见 peer”和“目标 group 可用数据提供者”。
建议 metadata 至少包含:
node role:bootstrap / fullnode / producer / relay;
supported protocols:rex、meshsub 等;
group membership;
latest block height / known group height;
data availability:是否声明可提供目标 group chain data;
timestamp / expiry。
第一阶段可以先做本地缓存和轻量握手,不强制签名。后续若与 #320 的 signed peer record / trusted registry 合并,可升级为 signed metadata。
P3:完善 provider scoring 与熔断
目标:把已有 scorer 框架用于 provider 质量排序,而不是让它承担身份/能力校验职责。
成功返回可应用 blocks 的 peer,提高 block provider score。
协议不支持、stream negotiation failure、group mismatch、无数据响应等应记录不同失败类型。
对连续失败的 peer 做短期熔断,避免反复重试同一无效 provider。
对 owner/producer/近期成功 provider 提高优先级。
保持一定探索比例,避免永久只选历史成功 peer。
P4:补充观测与测试
目标:让该问题可复现、可验证、可回归。
建议测试场景:
1 个 bootstrap/address-book 节点 + 2 个 fullnode。
fullnode 加入 group,但尚未连接到 owner/fullnode 时,syncer 不应向 bootstrap-only peer 发 Rex 请求。
topic peers 为空且 fallback 关闭时,应产生明确的无可用 group peer 日志/指标。
两个 fullnode 显式互连或通过 group topic 互相可见后,syncer 应能从 owner/fullnode 同步 block。
peer 不支持 Rex 协议时,应被协议能力过滤或记录为 protocol mismatch,而不是普通重试超时。
建议指标/日志:
rex_provider_candidates_total;
rex_provider_filtered_total{reason="no_rex_protocol|not_group_member|bootstrap_only|no_data|bad_score"};
rex_provider_selected_total{source="topic|trusted|fallback"};
rex_request_failed_total{reason="protocol_mismatch|stream_error|timeout|block_not_found|group_mismatch"};
rex_sync_no_group_peers_total。
本 issue 可以作为 #320 的 P1/P2 工程落地点之一:#320 解决 discovery 不应作为共识关键权威来源;本 issue 解决 syncer 不应把任意可见 peer 当作 group data provider。
更稳妥的整体方向是:
依赖风险审计备忘:go-libp2p-kad-dht DHT 发现机制的 Sybil/审查风险 #320 :将开放 DHT 降级为非关键 fallback 或显式 opt-in discovery backend。
改进 fullnode/syncer 的 group peer 选择与 rex provider 过滤 #322 :在 Rex syncer/provider selection 层做硬性能力过滤、group provider metadata、provider scoring 和结构化诊断。
后续可将 trusted bootstrap、allowlist、链上成员列表、signed peer record 与 provider metadata 合并,形成更明确的 group peer registry。
预期收益
减少无效 Rex 请求和重试等待;
提升新 fullnode 加入 group 后的同步收敛速度;
降低 DHT/自动发现/connected peers 质量对同步路径的影响;
让 bootstrap/address-book、fullnode、producer 的职责边界更清晰;
为后续共识和同步协议升级提供更稳健的网络层基础。
建议验收标准
group Rex sync 不再默认向所有 connected peers fallback。
syncer 选择 provider 前能过滤不支持 Rex 协议的 peer。
bootstrap/address-book-only peer 不会被默认当作 group block/data provider。
至少有一个测试覆盖 bootstrap-only + fullnode 显式互连后的同步行为。
provider 过滤和失败原因有结构化日志或指标可观测。
这是一个设计/audit 备忘,不是 bug 报告。它与 #320 有背景关联,但不是同一个议题。
背景
在常见拓扑中,bootstrap/address-book 节点主要负责 peer 引导和发现入口;fullnode/producer 节点才实际持有 group block/data,并可作为同步数据提供方。
本地联调中观察到一个值得记录的现象:fullnode 加入 group 后,如果自动发现或初始连接阶段只连接到了 bootstrap/address-book 节点,而尚未发现或连接到 group owner/fullnode,syncer 可能无法从合适的数据提供方同步。bootstrap 节点通常不承担 group block/data provider 职责,也不一定支持 Rex 协议;当后续两个 fullnode 显式互连后,syncer 可以正常从 owner/fullnode 同步到目标 block 和内容。
这说明问题重点不在于 bootstrap 是否应该承担数据同步职责,而在于 fullnode/syncer 选择 Rex provider 时需要更明确的 peer 能力、group 角色和数据可用性过滤。
当前源码链路
当前 Rex 请求链路大致如下:
RexSyncer.syncBlockTaskSender()构造REQ_BLOCK请求,并调用ConnMgr.SendReqTrxRex()。ConnMgr.SendReqTrxRex()从 group user topic 获取psconn.Topic.ListPeers()。RexService.Publish()优先使用传入的channelpeers;如果channelpeers为空,则回退到Host.Network().Peers()。RumGroupPeerStore.filterPeers()会过滤 bad response peers,并基于 block provider scorer / capacity 做排序与裁剪。PublishToPeerId()对候选 peer 创建 Rex stream;如果 peer 不支持 Rex 协议或连接失败,会计入 bad response。因此,问题更准确地说不是“DHT 结果直接进入 Rex provider 列表”,而是:DHT/bootstrap/manual/pubsub peer exchange 发现并连接的 peer 会间接影响 pubsub topic peers;当 topic peers 为空时,当前逻辑还可能回退到所有 connected peers。这样会让 bootstrap/address-book-only peer 或不具备目标 group 数据能力的 peer 成为 Rex 请求候选,导致无效请求、重试等待和同步收敛变慢。
现状缺口
/quorum/<network>/rex/2.0.0。成熟实施方案建议
P0:限制 group sync 的候选来源
目标:先避免把明显不合适的 peer 当作 Rex provider。
ErrNoGroupPeersAvailable,而不是对任意 connected peer 发 Rex 请求。P1:Rex 请求前做协议能力过滤
目标:在创建 Rex stream 之前过滤掉确定不支持 Rex 的 peer。
P2:引入 group provider metadata
目标:让 syncer 能区分“网络层可见 peer”和“目标 group 可用数据提供者”。
建议 metadata 至少包含:
第一阶段可以先做本地缓存和轻量握手,不强制签名。后续若与 #320 的 signed peer record / trusted registry 合并,可升级为 signed metadata。
P3:完善 provider scoring 与熔断
目标:把已有 scorer 框架用于 provider 质量排序,而不是让它承担身份/能力校验职责。
P4:补充观测与测试
目标:让该问题可复现、可验证、可回归。
建议测试场景:
建议指标/日志:
与 #320 的关系
本 issue 可以作为 #320 的 P1/P2 工程落地点之一:#320 解决 discovery 不应作为共识关键权威来源;本 issue 解决 syncer 不应把任意可见 peer 当作 group data provider。
更稳妥的整体方向是:
预期收益
建议验收标准