Skip to content

改进 fullnode/syncer 的 group peer 选择与 rex provider 过滤 #322

Description

@liujuanjuan1984

这是一个设计/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 请求链路大致如下:

  1. RexSyncer.syncBlockTaskSender() 构造 REQ_BLOCK 请求,并调用 ConnMgr.SendReqTrxRex()
  2. ConnMgr.SendReqTrxRex() 从 group user topic 获取 psconn.Topic.ListPeers()
  3. RexService.Publish() 优先使用传入的 channelpeers;如果 channelpeers 为空,则回退到 Host.Network().Peers()
  4. RumGroupPeerStore.filterPeers() 会过滤 bad response peers,并基于 block provider scorer / capacity 做排序与裁剪。
  5. 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 请求候选,导致无效请求、重试等待和同步收敛变慢。

现状缺口

  1. bootstrap/address-book peer 与 group data provider peer 的角色边界不够显式。
  2. syncer provider 选择目前主要依赖 topic peers、connected peers fallback 和历史评分,不够依赖协议能力、group membership 和数据可用性。
  3. topic peers 为空时回退到所有 connected peers,对 group sync 来说风险较高,容易把非 group data provider 当作候选。
  4. Rex 请求前缺少明确的协议能力过滤:例如 peer 是否支持当前 network 的 /quorum/<network>/rex/2.0.0
  5. peer 元数据/握手能力不足时,syncer 难以在发起 Rex 请求前判断:peer role、目标 group membership、latest block height、是否可提供目标 group chain data。
  6. 现有 scorer 框架已经存在,但更偏历史响应质量;它不能替代发请求前的硬性能力过滤。
  7. provider 选择失败、协议不匹配、group 不匹配、无可用 group peer 等情况还需要更结构化的日志和指标,便于区分“网络未发现 peer”和“发现 peer 但不可提供数据”。

成熟实施方案建议

P0:限制 group sync 的候选来源

目标:先避免把明显不合适的 peer 当作 Rex provider。

  1. 对 group Rex sync,优先只使用 group user topic peers 或显式 trusted group peers。
  2. topic peers 为空时,不要默认回退到所有 connected peers;至少应通过配置控制该 fallback,生产默认关闭。
  3. 如果没有可用 group peers,返回或记录明确错误,例如 ErrNoGroupPeersAvailable,而不是对任意 connected peer 发 Rex 请求。
  4. bootstrap/address-book-only peer 默认不进入 group data provider candidate set。

P1:Rex 请求前做协议能力过滤

目标:在创建 Rex stream 之前过滤掉确定不支持 Rex 的 peer。

  1. 通过 libp2p identify / peerstore / protocol list 缓存 peer 支持的协议。
  2. 只向支持当前 Rex protocol id 的 peer 发起 Rex 请求。
  3. 对能力未知的 peer,可做一次轻量探测并缓存结果。
  4. 协议不匹配应计入结构化原因,而不是只表现为普通 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 质量排序,而不是让它承担身份/能力校验职责。

  1. 成功返回可应用 blocks 的 peer,提高 block provider score。
  2. 协议不支持、stream negotiation failure、group mismatch、无数据响应等应记录不同失败类型。
  3. 对连续失败的 peer 做短期熔断,避免反复重试同一无效 provider。
  4. 对 owner/producer/近期成功 provider 提高优先级。
  5. 保持一定探索比例,避免永久只选历史成功 peer。

P4:补充观测与测试

目标:让该问题可复现、可验证、可回归。

建议测试场景:

  1. 1 个 bootstrap/address-book 节点 + 2 个 fullnode。
  2. fullnode 加入 group,但尚未连接到 owner/fullnode 时,syncer 不应向 bootstrap-only peer 发 Rex 请求。
  3. topic peers 为空且 fallback 关闭时,应产生明确的无可用 group peer 日志/指标。
  4. 两个 fullnode 显式互连或通过 group topic 互相可见后,syncer 应能从 owner/fullnode 同步 block。
  5. 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。

#320 的关系

本 issue 可以作为 #320 的 P1/P2 工程落地点之一:#320 解决 discovery 不应作为共识关键权威来源;本 issue 解决 syncer 不应把任意可见 peer 当作 group data provider。

更稳妥的整体方向是:

  1. 依赖风险审计备忘:go-libp2p-kad-dht DHT 发现机制的 Sybil/审查风险 #320:将开放 DHT 降级为非关键 fallback 或显式 opt-in discovery backend。
  2. 改进 fullnode/syncer 的 group peer 选择与 rex provider 过滤 #322:在 Rex syncer/provider selection 层做硬性能力过滤、group provider metadata、provider scoring 和结构化诊断。
  3. 后续可将 trusted bootstrap、allowlist、链上成员列表、signed peer record 与 provider metadata 合并,形成更明确的 group peer registry。

预期收益

  • 减少无效 Rex 请求和重试等待;
  • 提升新 fullnode 加入 group 后的同步收敛速度;
  • 降低 DHT/自动发现/connected peers 质量对同步路径的影响;
  • 让 bootstrap/address-book、fullnode、producer 的职责边界更清晰;
  • 为后续共识和同步协议升级提供更稳健的网络层基础。

建议验收标准

  1. group Rex sync 不再默认向所有 connected peers fallback。
  2. syncer 选择 provider 前能过滤不支持 Rex 协议的 peer。
  3. bootstrap/address-book-only peer 不会被默认当作 group block/data provider。
  4. 至少有一个测试覆盖 bootstrap-only + fullnode 显式互连后的同步行为。
  5. provider 过滤和失败原因有结构化日志或指标可观测。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions