TrackPayment 盯一笔在途的闪电付款:五种状态、乱序陷阱与重启找回 图 1
TrackPayment 盯一笔在途的闪电付款:五种状态、乱序陷阱与重启找回 · 图 1

闪电付款提交后,钱是”在路上”还是”已经摔了”?listpayments 快照能回答”过去付成什么结果”,但盯一笔正在飞的单子要靠流式接口:router 服务里的 TrackPaymentV2 按付款哈希订阅这一笔的全部状态更新,TrackPayments 则一次性订阅所有未到终态的付款。本文按 LND v0.19.0-beta 的接口定义核对这条流的语义与边角。

一、流式接口与普通查询的分界

普通查询是”我问你答”,拉一次给一个瞬间;TrackPayment 是”我挂在你这儿,有变化你推给我”。客户端调用后保持长连接,LND 每当这笔付款的状态推进,就往流里推一个 Payment 对象——同一笔单子会推多次,中间态与终态都在流里。Payment 对象的状态字段一共五种:INITIATED 是单子建好还没发出任何尝试,IN FLIGHT 是有 HTLC 正在途中,SUCCEEDED 与 FAILED 是两种终态,还有一个已弃用的 UNKNOWN 声明永远不会返回。注意终态之后流就关闭,所以这条订阅是”一次性跟完一单”,不是永久监听。也正因为流会关,长生命周期的守护程序不能把它当消息总线用——正确模式是启动时先扫一遍未终态单子的清单,逐个建立订阅,流关了就说明这一单落定了,去台账里确认终态即可。

二、no inflight updates 开关

请求里的这个布尔参数为 true 时,中间的飞行态更新全部抑制,流里只在终态到来时给你一个最终对象。做用户界面的通常想要完整流——进度条要靠 IN FLIGHT 动起来;做批量对账脚本的更适合只看终态,连接压力小、逻辑简单。值得知道的是代价:放弃中间态意味着你看不到这一单尝试过几条路径、失败在哪一跳,排障期建议先关着开关看全流。

三、订阅时机与乱序陷阱

接口注释里写了一段重要的坑:对”所有未终态付款”的批量订阅(TrackPayments 或带过滤的用法)如果在已有付款在途时才建立,流的开头可能给出乱序甚至重复的事件。官方给出的纪律很明确:想不漏更新,就在发起任何付款之前先建立订阅。单笔哈希的 TrackPayment 没有这个问题——它按当前状态起步,把后续推进推给你,中途接上也不会重放历史。

四、Payment 对象里该盯什么

除了状态字段,流里每个对象都带付款哈希、付款请求原文与尝试记录:每次路由尝试叫一个 HTLC 尝试,各自带自己的状态、尝试时间、解决时间、失败原因与走过的路线。终态是 FAILED 时,这些尝试记录就是全部尸检材料——是费用超限、目标不可达还是通道额度不足,看失败原因枚举与路线就能定位。金额字段有按聪与按毫聪的多代版本同堂,读值前先确认字段名;fee msat 累计这一单实际付出的路由费,对账时它和发票金额相加才是总支出。

五、和相邻工具的搭配

发送侧用 SendPaymentV2 时本身就返回同一种流,TrackPayment 主要服务两类场景:付款进程与监控进程分离时,另一头凭哈希重新挂上;以及重启后把崩溃前在途的单子全部找回——按钱包账本里未终态的付款哈希逐个订阅即可,接口文档也提示重启用这个办法把”没回音”的单子重新纳入监控。想要的是历史汇总就用 listpayments 分页拉,别拿流接口重放历史:它设计上就不做历史回放。

风险提示:付款状态判读直接影响资金操作决策,请以链上与通道账本为最终依据;本文不构成任何投资建议。