lncli wallet leaseoutput:给 UTXO 上租约,防止多路任务同时选中同一枚币 图 1
lncli wallet leaseoutput:给 UTXO 上租约,防止多路任务同时选中同一枚币 · 图 1

一、这个接口为什么存在

闪电节点的钱包经常被多个流程同时掏:一条通道要开、一笔快速关通道要广播、几笔超时资金要回收,如果两个流程各自做选币,很可能挑中同一枚 UTXO,最后只有一笔能进块,另一笔报双花冲突。Bitcoin Core 用钱包内部的 coins db 加 lockunspent 管住这个问题;LND 的做法是给外部程序一把正式的”租约”:wallet leaseoutput 把一枚输出和某个调用者身份绑定,租约存续期间选币器不会再把这枚币发给任何人。本文按 LND v0.19.0-beta 的 walletkit.proto 注释与消息定义核对。

lncli wallet leaseoutput:给 UTXO 上租约,防止多路任务同时选中同一枚币 图 2
lncli wallet leaseoutput:给 UTXO 上租约,防止多路任务同时选中同一枚币 · 图 2

二、签发一把租约

请求消息里有三项。id 是三十二个随机字节,注释明确它必须在本 RPC 的每个独立应用之间各不相同——它是租约的所有权标识,谁持有这串字节,谁才能续期或提前释放;同一台机器上跑两个脚本共用一组随机字节,等于共用一把租约,语义就乱了。outpoint 是交易号加输出序号,指定要锁哪枚币。expiration_seconds 是租期秒数,填零则走默认时长,具体的默认值由底层 wtxmgr 租约管理器定义,注释本身不承诺数字,运维上把它当”几十分钟量级的会过期锁”来设防即可,想要长租就显式填。

响应只有一个 expiration:租约到期的绝对 Unix 时间戳。续期不需要另一个命令——再调一次同一个 RPC 即可,注释写明租约到期时间可以被反复调用顺延。

三、租约期间发生什么

被租出去的输出在租约有效期内从选币池里消失:开通道、wallet fundpsbt、wallet sendcoins 走到选币那一步,都会把它当作不存在。租约到期后,如果没有续期也没有释放,它自动回到可用池,不需要清理动作。提前释放用 wallet releaseoutput,传入与签发时同一串 id,币立刻可用。想知道当前都有谁在锁币,用 wallet listleases:返回按租约 ID 分组的未过期租约列表,每个租约再带上具体被锁的输出。

四、与 FundPsbt 内部锁的分工

上一类场景里 wallet fundpsbt 结尾提到过:FundPsbt 会用它自己的内部应用 ID 锁住参与交易的 UTXO。那是”交易进行中”的内部锁;leaseoutput 则是给调用方自己的锁——脚本要预留一批币慢慢用、跨几轮 RPC 保持同一次选币结果时,才需要显式租约。排障时 listleases 只看得见显式租约,不会显示 FundPsbt 这类内部锁,别看到列表空着就断定”没有锁”。

五、边界与自查

第一,租约只约束 LND 自己的选币逻辑。如果有别的软件直接拿私钥在链上花同一枚币,租约拦不住,它本质仍是进程内的信用约定。第二,多设备共享钱包文件、或者用 importaccount 把同一套密钥导入两个 LND 的场合,每台节点各自记各自的租约账,跨节点互不感知。第三,把三件事列进脚本规范:随机 ID 每个应用只生成一次并落盘、到期时间写入日志、任何失败分支调用 releaseoutput 或在确认广播成功后自然让租约过期。

六、租约在运维面板上的用法

租约机制对运维最直观的价值,是把『为什么这笔输入不可用』变成可查询状态。排查顺序可以固定下来:钱包余额与可用余额出现缺口时先跑 listleases,若缺口对应的输出挂着租约,看租约 ID 归属哪个应用、到期时间是否合理;租约早已过期而币仍不可选,问题多半在选币缓存或钱包同步,与租约无关。反过来,如果面板显示一切正常却仍报『没有可用输入』,要检查的是另一套锁——FundPsbt 类内部锁或正在组装的交易被卡在签名环节。把租约 ID 的生成与保存写进接入文档:随机字节建议用随机数生成器现生成后持久化到应用自己的配置,切勿每次启动重生成,否则旧租约到期前没有任何办法提前释放,只能干等。

风险提示:租约本身不动资金,但租约下的币可能被流程遗漏造成冻结。测试网演练后再上主网,本文不构成投资建议。