致命与不致命分开了:闪电网络的error和warning消息怎么划分损失 图 1
致命与不致命分开了:闪电网络的error和warning消息怎么划分损失 · 图 1

闪电节点之间的对话里,有两类消息负责说“你那边有问题”。一类是 error,对方收到后必须把涉及的通道判死;另一类是 warning,对方只需把它记进日志,连接和通道都继续活着。闪电的基础消息规范(BOLT 1)把这两者列成相邻的小节,字段结构几乎一模一样,差别全在后果上。理解这条分界线,是读懂闪电节点日志的第一步。

两条消息的字段长什么样

error 的消息类型号是 17,warning 是 1。两者都携带三个字段:一个通道编号、一个长度、一段按该长度给出的文字。通道编号如果全零,就表示“与你的所有通道”而不是某一条。文字部分可以是空的;规范建议实现只放可打印的 ASCII 字符,否则接收方不应该把它原样打印出来——这段文字是给人排障看的,不是给机器解析的。

在通道还没完全建立的早期阶段,双方手里还没有正式通道编号。规范为此规定:在开通道流程的早期,error 消息要用一个临时通道编号代替正式编号,等资金交易签名交换完成后才换回正式编号。这是新手读日志时最容易迷路的地方——同一条通道在建立前后各有一个编号。

致命与不致命分开了:闪电网络的error和warning消息怎么划分损失 图 2
致命与不致命分开了:闪电网络的error和warning消息怎么划分损失 · 图 2

后果完全不同

发送 error 的一方要承担义务:凡是发出 error 所指的通道,自己也必须把这些通道置为失败;如果编号全零,则代表与该对等端的所有通道全部作废。接收方的义务对称:编号指向哪条通道,就把那条通道判死。

warning 则温和得多。接收方“应该记录该消息以便日后诊断”,如果想体面收场,也可以在允许的阶段尝试发起关闭,但没有任何一条通道因为收到 warning 而必须死亡。规范甚至专门解释了这种设计的来历:早期实现里 error 被滥用,一些本来可以重试的偶发小问题也会直接拆掉通道,于是节点软件干脆选择忽略 error 来避免昂贵的通道中断;warning 正是为这类“可以重试、可以恢复”的场景补上的分级。

还有一个容易忽略的细节:当一方收到与自己无关、找不到对应通道的消息时,规范要求它忽略并回一条指向该未知编号的消息,而不是断开连接。这把“对方发错了”和“对方是坏人”区分开来。

什么时候该发哪条

规范给出的默认倾向是:协议违规或让通道无法继续的内部错误,发 error;对未知通道消息的答复、可恢复的异常、以及值得告知但不致命的提示,发 warning。签名验证失败是一个特殊场景——在涉及资金交易创建、资金签名、关闭签名或承诺签名的消息上出现签名检查失败时,发送方应该在回复里附上那笔原始交易的十六进制编码,方便对方定位到底签错在哪。生产环境里还有一种隐私考虑:透露错误细节可能泄露信息,所以 data 字段被设计成可选,许多实现只发空文本。

快速问答

问:节点日志里刷出一堆 warning,需要立刻关通道吗?

答:规范层面不需要,warning 的本意就是“记账不改状态”。但同一个来源反复出现同一类 warning,往往意味着两边软件对协议的理解有偏差,值得检查版本或上报开发者。

问:收到 error 之后资金会怎样?

答:被判失败的通道不会自动上链。持有最新状态的一方可以无条件关闭通道取回自己的余额;如果你手上是旧状态而对方是新的,才存在被对方用旧机制追索的风险,这也是备份与监视机制存在的意义。

常见误区

一是把 warning 当 error 处理,看到示警就手动拆通道,白白付出链上手续费并中断收款。二是把 error 当网络抖动忽略,规范上它已经触发了双方的通道失败流程,拖着不处理只会让两边的状态假设越差越远。三是以为示警文字是标准错误码,实际上那只是自由文本,跨实现没有统一含义,判断后果只能看消息类型本身。

风险提示:本文为协议机制科普,不构成任何投资建议;通道状态处理涉及资金,请参照官方规范与所用实现的文档操作。