waitfornewblock超时算新区块吗? 图 1
waitfornewblock超时算新区块吗? · 图 1

Bitcoin Core waitfornewblock 可长轮询链尖变化,但超时也会返回当前区块。本文用 current_tip、毫秒超时、返回哈希比对与重组处理设计可靠监听器。

waitfornewblock 的调用会在区块变化或超时后返回,但两条路径的响应形状相近。监听器如果把“收到响应”直接映射成“新增区块”,会在每次超时制造假事件,甚至把同一高度重复写入下游。

返回一次不代表出现新区块

timeout 以毫秒为单位,默认 0 表示不超时;发生超时或进程退出时会返回当前区块。 因此监听器不能写成“RPC 返回就发布新区块事件”,而要比较返回 hash 与 lastProcessedHash。

bitcoin-cli -rpcclienttimeout=0 waitfornewblock 30000 "<CURRENT_TIP_HASH>"

timeout 是毫秒;服务端 timeout=0 表示不超时,命令行长轮询还要避免客户端先行断开。

current_tip怎样建立观察基线

传入 current_tip 时,方法等待链尖与该哈希不同;bitcoin-cli 长轮询应使用 rpcclienttimeout=0。

持久化的 current_tip 是监听器状态,不是临时变量。进程重启后从它恢复,才能知道第一次返回是新链尖、同一链尖心跳,还是离线期间已经跨过多个区块。

超时重连与客户端超时的双层控制

WAITING
  ├─ 返回hash相同 → TIMEOUT_HEARTBEAT → 再等待
  ├─ 返回hash不同且连接上旧tip → NEW_TIP → 处理新区块
  └─ 返回hash不同且父链不接续 → REORG → 回滚并重放
  1. 启动时读取并持久化当前链尖哈希。
  2. 以已处理哈希作为 current_tip 调用。
  3. 收到响应先比较哈希,再判断是否有变化。
  4. 变化后按父哈希关系补齐或回滚下游。
  5. 无变化则记录心跳并重新进入等待。

waitfornewblock 等待任意新区块,并返回区块哈希和高度。 调用方必须把返回值与上次已处理哈希比较,因为超时返回不等同于发生新区块。

重组场景下如何避免漏处理

假设监听器设置三十秒 timeout,网络在这段时间没有新区块。RPC 仍会返回当前 hash 和 height;如果代码只判断响应非空,就会重复触发通知。另一个场景是同高度哈希改变,此时不能按“高度未增加”忽略,因为那可能是重组后的新链尖。

重组时高度可能相同而哈希不同,也可能一次跨越多个高度。下游以区块哈希和父哈希建幂等键,不用“高度只增不减”作为程序不变量。

区块监听器的失败状态机

  • 把超时返回记录成一个新区块。
  • 只比较高度而不比较区块哈希。
  • 客户端默认超时早于服务端等待。
  • 进程重启后丢失最后已处理链尖。

监听器日志至少保存等待起点、返回值、返回原因、耗时和最终动作。只有心跳的周期不要制造业务通知。

长轮询运行记录和验证资料

在 regtest 运行三组测试:无出块等待到超时、生成一个新块、让保存基线与当前链尖不同。复核者检查事件数必须分别为零、一和一,并确认每次判断都引用哈希而非仅引用高度。

链尖变化只代表节点当前观察,不等于达到业务最终性。通知、索引和资金入账应采用各自确认策略,并能处理断线、重启和短重组。

生产监听器最好把 lastProcessedHash、lastProcessedHeight 和处理事务号写入同一持久化记录。收到新链尖后,先沿父哈希回溯到共同祖先,再在一个幂等事务内撤销旧分支、写入新分支。通知系统消费已提交事件,不直接消费 RPC 返回,避免数据库失败时仍向用户报出新区块。

当前未知:实际 HTTP 代理、负载均衡器和客户端库可能另设超时,需按部署环境配置心跳与重连。

分叉与连接排障可看 getchaintips识别分叉节点连接检查getrpcinfo长请求