listinvoices 翻发票台账:四格状态机与两套索引的增量对账 图 1
listinvoices 翻发票台账:四格状态机与两套索引的增量对账 · 图 1

闪电节点收过的发票存在哪里、状态怎么翻旧账,是运营和排障都绕不开的问题。lncli 的 listinvoices 就是这台发票台账的翻账命令:它不改任何状态,只把节点内存过的收款请求按索引摊给你。本文按 LND v0.19.0-beta 的接口定义核对它的字段与翻页姿势。

一、四格状态机

每张发票有一个 state 字段,取值只有四种。OPEN 是签发后还没人付,或者付了第一笔但没收齐——这里藏着一个常见误解:一张发票允许多次付款尝试,只要没全额结清,状态仍停在 OPEN。ACCEPTED 是钱已到、等待业务方放行——配合持有型发票场景,节点先收下 HTLC 再决定结不结。SETTLED 是结清,带着结算时间和预镜像。CANCELED 是被本地取消,已挂在该发票上的在途尝试会随之失败。注意”过期”不是状态:一张没人付的发票过了到期时间仍然是 OPEN,台账不会自动改成作废,判断过期要自己比较时间戳。

二、两套索引,两套时间线

发票对象里有两个容易混淆的编号:add_index 是这张发票被创建时按”签发顺序”分的号,settle_index 是结清时按”结算顺序”分的第二套号。为什么两套:签发和结清是两件事,先发的票可能后结。做增量同步时,用哪套取决于你订阅的事件——关心”有人付款了”就按 settle index 追,关心”我开出了哪些票”就按 add index 翻。listinvoices 返回里带 first index offset 与 last index offset,就是这个游标翻页的锚点。

三、翻页与过滤参数

index offset 加 num max invoices 决定从哪个号开始取多少张;reversed 把方向调转,从最新往回翻——日常巡检”最近收了哪些”务必带它,否则默认从最老的票开始数。pending only 过滤只留未结清的,查坏账好用;creation date start 与 creation date end 按签发时间圈窗口,适合日报表。四个条件可以组合,但记住过滤发生在分页之上:先筛后翻页,每页的含义会随筛选集变化,脚本断点续传时把游标和过滤条件一起存,别只存游标。

四、和相邻命令的分工

listinvoices 看”我收过的”,listpayments 看”我付过的”,lookupinvoice 按单票精确查。发票对象里的付款请求原文可以喂给 decodepayreq 拆字段;金额字段有几代同堂现象,新旧字段单位分别是毫聪与聪,跨版本迁移脚本先确认自己读的哪一个。预镜像是结清证明的核心:拿到 settle 状态的票,对应的付款预镜像就是向对方证明”这笔付款完成了”的凭据,保管逻辑应当与敏感数据同级。再往订阅侧走一步,subscribeinvoices 提供流式推送,新票签发与状态跃迁实时到达;报表与巡检用 listinvoices 分页,实时联动用订阅流,两条通道并用时以索引号做去重,事件与台账才不会记成两笔。

五、实战建议

对账系统建议定时全量翻一遍 add index 区间而不是只看事件回调,防止回调丢失造成漏账;发现大量 OPEN 状态的过期票,说明流量到门口没进门,该查的是路由可达性和通道入向容量而不是发票本身;OPEN 转 ACCEPTED 长时间不转 SETTLED,是业务侧忘了调用结算接口,属于流程 bug 不是网络故障。最后一类值得单独提防:同事或脚本用同一份助记词在不同机器上重建了节点,两边各自记了一套发票索引——listinvoices 只看得到当前这台机器的账,链上通道里真实发生的收款要回到通道账本与链上数据去对齐,发票台账从来不是资金事实的源头,只是节点自己的记事本。

风险提示:本文描述收款台账机制,不涉及任何经营或投资建议;对账系统的资金判定请以链上与通道账本为准。