Porting Couter Strike to Fiber network

我觉得这是一个很棒的Fiber integration demo.

在我的理解这应该是一个 权威性/中心化的 1v1 session-based game,外接 Fiber 作为 事件驱动结算侧车。

简单梳理一下:

  • 实时对战仍然是传统 UDP/Renet, Renet 仍然要负责延迟敏感的输入和快照;
  • Fiber 负责把预先授权的支付条件,在服务器判定伤害后兑现。且 Fiber 恒仅处理 pre-authorised value transfer;
  • 热路径 和 结算路径 分离。
  • 托管边界是服务器和 matchmaker 不接触玩家的 wallet key,也不代理玩家的 FNN RPC
  • 伤害累计每跨过一个 25点伤害的 bucket,就释放一张对应 invoice 的 preimage
  • 服务器在伤害发生后释放 preimage,payer 到这个时候也没有了拒付点,那么既然对应 preimage 被释放,付款就无法被输家撤回。

这已经是一个相当自洽的 MVP 模型和优秀的 base line 了. 也对我有一些模型设计上的启发。

最近两个月,我也在频繁思考 gaming、通道网络,以及 Xuejie-style 的 CKB-VM-isomorphic off-chain session runtime 应该如何更自然地结合。期间有一些相似的问题同样困扰着我,所以我想冒昧在这里分享一些思考:

0. 如何尽可能降低 channel onboarding 的存在感?

因为在这个相对简单的模型中,双方仍需要:

  • 各自运行本地 FNN;
  • 准备测试币;
  • 找到对方身份;
  • 事先建立直接通道;
  • 确保双向的 outbound 流动性;
  • 启动游戏客户端。

对于普通玩家可能仍然不可接受。

我好奇在未来我们是否可能把这些步骤压缩为无感的流程?:

Join Room
→ embedded non-custodial wallet/FNN
→ automatic route and liquidity check
→ just-in-time channel or LSP provisioning
→ authorise a bounded session cap
→ start game

1. 服务端的oracle风险怎么处理?

在类似方案中,host server 可能掌握所有 preimages, 那么服务器本身、管理员或 签名设施 被攻破的时候,攻击者可以在没有合法伤害的情况下释放全部 preimages,将每位玩家的整个 pre-authorised cap 结算出去。当然 Cap 的设计使损失有限度,但没有移除信任。

我考虑过一些方案, 一些可能的 hardening 方向包括:

  • 游戏服务器结算signer 分离;
  • 使用 短生命周期的、match-based keys (当然单纯增加签名者数量并不等于直接证明游戏结果正确。只是所有危机状态下的爆炸半径。加密通信上用的各种session key算法可能是一种参考。)
  • 持久化 append-only settlement log作证;
  • 扩展字段,让每次 release 绑定 sequence、match state commitment 等;
  • 为 争议审计 设法预先保留 确定性的输入转译

2.多方可扩展性的问题

如果多人模式继续沿用成对的直接通道,那么随着参与者数量增加,最终很容易逼近 O(n^2) 的 通道关系。那么产品化的阶段可能就要继续扩展前面说的无感化流程,引入 LSP/hub、嵌入式 wallet/FNN、自动流动性供应 和 round-level 或者match-level 的信用抽象。

在CS2的 5v5 场景里,严格来说可能未必需要十名玩家之间全部互连,但每位玩家至少可能与五名对手发生经济关系,仍然会产生明显的 对间流动性(pairwise liquidity)负荷 和 通道管理负荷。

LSP 或 hub 可以轻松把 通道拓扑 从近似 O(n^2) 降到接近 O(n)),但它不一定自动解决这个 shared bounded liability across multiple possible payees 的问题。目前我暂时还没有想到完美的方案。

3. Per-event invoice 怎么处理长时间、大量事件的游戏?

我之前做了一点调研, Counter Strike 2 每一个match的平均 kill 数量 还挺大的

当前汇总约:

37 million matches
748.6 million rounds
5.4 billion kills

用这些经过取整的总数计算​ ≈ 20.2 rounds/match​ 和 146 kills/match

因此,一场普通 match 的 kill 数量大约是 146

我们假设 CS2 玩家每 round 从 100 HP 开始,且 round 内通常不回血。若粗略把每次 kill 对应 100 HP depletion 切成四个 25-damage buckets,触发全局总致命伤害 可以非常粗略得视为 584 个 25-HP threshold-crossing 事件,

换句话说以FPS为例的话, 真实生产环境中的 FPS 一局可能产生数百次可结算伤害的事件。同样的估算方法在Valorant中适用的话, 那么 5V5 的 match 会很轻松突破上千次threshold-crossing 事件。

这在小规模的demo/局域网游戏session中完全没有问题,但是如果有发行方/运营方想要商业运营的时候,

为每次事件预建一张 hold invoice 会很显著地增加:

  • TLC 槽位占用压力
  • 流动性被长期锁定的问题
  • 赛前初始化延迟
  • 取消、超时与故障恢复复杂度
  • 恶意占用资源与 griefing 攻击面

4. 是否可以采用 round-level 或 short-epoch netting?

在规模化场景里,一个可能的取舍是采用 round-level netting,或者更短的 epoch-based netting,而不是为每个 damage bucket 都立即建立独立的最终支付。

例如,玩家双方先各自授权一个最大 exposure:

Player A max liability: 4 units
Player B max liability: 4 units

在 round 或 epoch 内,系统只维护一份签名的 cumulative economic ledger:

A inflicted 75 damage on B → B owes A 3 units
B inflicted 50 damage on A → A owes B 2 units

Gross settlement:
B → A: 3
A → B: 2

Net settlement:
B → A: 1

这样,五次 gross damage-bucket settlements 最终可以压缩成一次 net settlement。

整体结构可以变为:

Renet hot path
→ authoritative game simulation
→ signed cumulative economic checkpoint
→ bounded net obligation
→ Fiber settlement

玩家仍然可以在 session start 时预授权最大 exposure,但过程中不必为每一个细粒度事件立刻消费一张独立 invoice。

如果最终净额必须支持 0 ~ N 之间的任意值,可以考虑 binary-denominated reservations做为一个一个trick,例如:

1, 2, 4, 8, 16, ...

从而用 O(log N) 张 hold invoices 表示较大的金额范围。

5. Liquid Cells 给我的另一个启发:checkpoint 是可重建的

我之前参与了这篇讨论:

这其中对我最有启发的,不只是 netting 本身,而是一个更一般的原则:

一个 state commitment 最好不仅仅是 opaque hash,还应当存在足够的 underlying data,使其他参与者可以重建并验证它。

如果把这个原则应用到这个模型,一个 economic checkpoint 也许可以包含:

struct EconomicCheckpoint {
    match_id,
    epoch_id,
    sequence,
    previous_checkpoint_hash,

    gross_debits,
    gross_credits,
    net_balances,

    consumed_reservations_bitmap,
    game_transcript_root,
    expires_at,

    server_signature
}

这样,客户端、watchtower 或 replay service 至少可以验证:

  • checkpoint sequence 是否连续;
  • debit/credit 是否守恒;
  • net balance 是否计算正确;
  • 某张 invoice 是否已经被消费;
  • 某次 release 是否重复;
  • settlement amount 是否超过 session cap;
  • server restart 后是否可以从最后一个 checkpoint 恢复。

这仍然不能直接无信任地证明某一枪是否真正命中,也不能自动移除 authoritative server,但至少可以让历史变得可审计、可重建。

6.当然Netting 本身也有代价

Per-event 结算天然的优点是,每个 damage bucket 一旦释放,就获得独立finality。Netting 会把 finality 推迟到 round 结束 或 epoch checkpoint交界。这样一来,如果服务器在 checkpoint 前崩溃或消失,玩家之间可能存在尚未结算的经济状态。

因此如果 match netting 可能过于粗糙,一个合理的折衷也许是:

  • round-level checkpoint?
  • 或者每 10–30 秒一个 short epoch;
  • 持久化最新 checkpoint 和 reservation state;
  • server restart 后从最后一个有效 checkpoint 恢复;
  • 对未完成 epoch 使用明确的 timeout、forfeit 或 rollback rule。
6 Likes