# Fiber 中心化分账的集成方案设计 ## Metadata **Status**:: #x **Zettel**:: #zettel/literature **Created**:: [[2024-10-14]] %% (**Notion**:: [notion.site](https://cryptape.notion.site/Fiber-11b8f0d3781e80ee9a72e619ba7429e2?pvs=4)) %% ## Synopsis Fiber 中心化分账的目的是在用户不方便使用全功能 Fiber 节点时,维护中心化的账本为用户提供代理接入 Fiber 的服务。后方中使用“代理商”来代称提供 Fiber 代理服务的服务商,使用“用户”来特指使用该代理服务的用户。 代理商运行 Fiber 节点,并维护账本来记录用户余额。账本可以是中心化的,比如保存在代理商的数据库中;也可以是去中心化的,比如通过链下状态更新链上仲裁的合约。这里不讨论账本的实现细节,会假设代理商已经实现该功能。 为了方便该场景,Fiber 需要提供以下功能: 1. 代理商的 Fiber 节点收到订单要有办法确认收款人是哪个用户 2. 代理商能从 Fiber 节点同步所有成功支付的订单信息,包括发出和收到的。也就是通过 RPC 能够不重复不遗漏的同步成功支付的订单信息。该同步过程能在 Fiber 节点或者代理商的同步服务重启后自动恢复。 ## 整体设计 采用 [[Fiber 中心化分账的三种方案#方案三、LSP 记录 Payment Hash 和 LSP User 的映射]],由代理商在 Fiber 节点之外记录 Payment Hash 和用户的关联。 ## Fiber 功能设计 ### 支付同步 Fiber 需要提供按照 RPC 来查询 Invoice 和 Payment Hash 查询支付状态的 RPC,包括发送出去和收到的支付订单。 #### RPC `get_invoice` 查询通过 `new_invoice` 创建的 invoice 信息和状态。 Request: - `payment_hash (H256)` Response,如果存在对应的 invoice 则返回以下字段,否则返回 `null`. - `invoice (CkbInvoice)`: invoice 信息 - `status (string)`: invoice 状态,one of "unpaid", "paid", "expired" 其它字段可参考 [cln listinvoices](https://docs.corelightning.org/reference/lightning-listinvoices) 和 [lnd invoice](https://lightning.engineering/api-docs/api/lnd/invoices/lookup-invoice-v2#lnrpcinvoice) #### RPC `get_payment` 查询通过 `send_payment` 发送的 payment 信息和状态。 Request: - `payment_hash (H256)` Response,如果存在对应的 payment 则返回以下字段,否则返回 `null`. - `status (string)`: payment 状态,one of "pending", "failed", "complete" 其它字段可参考 [cln listpays](https://docs.corelightning.org/reference/lightning-listpays) 和 [lnd payment](https://lightning.engineering/api-docs/api/lnd/lightning/list-payments#lnrpcpayment) ## 代理商功能设计 ### 收款 用户需要收款时由代理商通过其 Fiber 节点创建 Invoice。该过程不需要用户在线。创建 Invoice 之后,代理商需要在其数据库的 invoices 表中保存以下 tuple (payment hash, status, user id) 然后 - payment hash: `new_invoice` RPC 返回的 payment hash - status: invoice status,初始为 `unpaid` - user id: 代理商内部的用户标识 代理商需要定时通过 `get_invoice` 同步状态。取出 invocies 表中所有 status 为 `unpaid` 的 (payment hash, status, user id): - 通过 payment hash 调用 `get_invoice` - 如果 invoice status 为 `expired`, 更新数据库中对应 invoice 的 status - 如果 invoice status 为 `paid`,更新账本和数据库中对应 invoice 的 status。两个更新操作要保证原子性。 ### 支付给同一代理商的用户 用户支付给同一代理商的用户时,代理商可以直接更新账本并添加支付者和收款者分别在 payments 和 invoices 表中的数据。而 Fiber 节点中的 invoice 可以放着不管,让其过期。 ### 支付给 Invoice 用户可以选择支付给 Invoice,如果 Invoice 的收款节点就是该用户的代理商,则代理商可以在保证原子性的前提下完成以下更新: - 更新账本中订单双方的余额。 - 将 invoices 表中对应 invoice 的 status 更新为 `paid` - 在代理商数据库的 payments 表中保存以下 tuple (payment hash, status, user id) - payment hash: invoice payment hash - status: `complete` - user id: 支付者的用户标识 如果 Invoice 的收款节点是其它节点,则代理商需要通过 Fiber 节点进行支付 - 使用 `send_payment` 支付 - 在代理商的数据库的 payments 表中保存以下 tuple (payment hash, status, user id) - payment hash: `send_payment` 返回的 payment hash - status: payment status, 初始为 `pending` - user id: 代理商内部用户标识 代理商需要定时通过 `get_payment` 同步状态。取出 payments 表中所有 status 为 `pending` 的 (payment hash, status, user id): - 通过 payment hash 调用 `get_payment` - 如果 payment status 为 `failed`, 更新数据库中对应 payment 的 status - 如果 payment status 为 `complete`,更新账本和数据库中对应 payment 的 status。两个更新操作要保证原子性。