等一块新块的耐心:GBT 长轮询的挂起与续订规矩 图 1
等一块新块的耐心:GBT 长轮询的挂起与续订规矩 · 图 1

在矿池与矿机的世界里,“等多久发一次新任务”是个比听起来的更值钱的问题。getwork时代的答案是矿工每秒问一次”有活吗”;getblocktemplate(GBT)时代的答案写进了BIP-22的一个可选章节:长轮询。本文按规范原文拆解这套挂起与续订的规矩,以及每个字段防的是什么事故。

从轮询说起:旧模式浪费的是什么

早期挖矿的getwork模式下,矿机不断向服务器轮询任务:每次都是完整的HTTP请求-响应,绝大多数时候答案是”还没新区块”。浪费分三层:网络带宽与服务器算力、任务下发的延迟(新区块出现到下一次轮询之间有空窗)、以及大量无用请求让代理与防火墙上的流量画像变得清晰。长轮询的改法一句话:把”每隔几秒问一次”变成”问一次,让服务器憋着,直到真的有东西可说”。请求不再立即返回,而是挂在服务器上,直到状态变化那一刻才带着新数据结束——延迟从”轮询间隔的一半”量级压到接近零,空转请求几乎清零。

等一块新块的耐心:GBT 长轮询的挂起与续订规矩 图 2
等一块新块的耐心:GBT 长轮询的挂起与续订规矩 · 图 2

握手:longpollid 与 longpolluri

BIP-22把这套机制定义为可选扩展。支持长轮询的服务器在区块模板响应里MUST包含longpollid字段,且它对每个事件唯一、不得复用——规范举例说一个只关心新区块的服务器可以拿上一个区块的哈希当它,但客户端不得假设这个字符串有任何特定含义,只当不透明令牌用。服务器还可以给出longpolluri:一个相对或绝对的备用地址,甚至可以是完全不同的资源与端口;一旦提供了它,客户端MUST只用这个URI发起长轮询请求。矿工侧的宣告则是capabilities列表里带上longpoll字符串,告诉服务器自己玩得这套。

发起挂起请求的方式就是普通JSON-RPC调用,只是把服务器之前给的longpollid填进请求参数,授权与原连接一致。规范对服务器的期望是否定式的:在准备替换该longpollid对应的当前区块数据之前,这个请求SHOULD NOT被处理或应答——响应本身不存在超时上限,“憋多久”完全由链上事件决定。

挂起请求的三条生存守则

第一,客户端SHOULD把这条请求的超时设得非常长,并且MUST接受服务器提前发出部分响应的行为——规范点名了HTTP分块传输的场景:服务器可以先发响应头,最终JSON等事件到了再补完。不理解这点的HTTP库会傻等在”响应不完整”上,或过早超时重发,把长轮询做回轮询。

第二,收到完成响应之后动作有明确顺序:立刻开始做新任务(规范说越快越好,“submitold”为false时MUST立即转做新工作),同时对同一长轮询URI再发起新的挂起请求——挂起队列永远保持一条在途,事件到来与下一次挂起之间的间隙才最小。这里submitold值得单独讲:它是长轮询响应里的布尔提示,缺省含义是”此前收到的工作仍可能有效,份额照常提交”;为false时,服务器在告诉矿工”旧任务作废,可以清空未提交的份额队列”。两种模式下矿池的记账口径完全不同,客户端不得自行猜测。

第三,失败处理。响应不完整或无效时,客户端SHOULD以指数退避重试,可以设上限、算法自选,但规范划了一条红线:失败超过一次后,禁止立即无延迟重试——这条防的就是链尖频繁重组或服务器抖动时,客户端以请求洪水打垮本就脆弱的端点。而如果收到”Forbidden”类响应(规范举例如HTTP 403),客户端SHOULD NOT在无人介入的情况下自动重试:被明确拒绝的凭据或来源,重刷没有意义。

这套机制今天活在哪些角落

需要把生态位说清:BIP-22/23(后者扩展到P2P挖矿场景,含块模板提交约定)状态均为Deployed,但”部署”的主体是矿池服务器、挖矿代理与独立矿工的直连方案这一侧——今天主流矿机与矿池之间的Stratum协议族走的是另一条路线(服务器主动推任务,等价于把长轮询的意图做进了协议本身)。长轮询真正的当代用户,是那些把自建节点/代理与HTTP接口串联起来的方案:自挖软件经代理把GBT模板下发给矿机、钱包或工具借挂起请求监听链上任务变化。理解了BIP-22这一章,再看任何”挂起等待型”API(包括链上服务常用的类似手法)都是同一套母题的变体:用一个不透明ID锚定”你在等哪个世界状态”,用挂起消除空轮询,用退避和禁权重试保护服务端。

风险提示

本文是接口规范的技术解读,不构成投资建议,也不构成对任何矿池或代理支持上述可选字段程度的担保(以各实现文档为准)。文中规范性用词(MUST/SHOULD及其约束)与字段定义以bitcoin/bips仓库中BIP-22当期文本为准,版本状态(Deployed)为2026年10月核验结果。