在加密貨幣採礦的體系中,Stratum V1 協議充當著礦池與礦機之間最核心的通信橋樑。本專題解析將深入探討礦池如何從比特幣全節點取得區塊模板、將其切分為高效的工作包下發,以及礦機在收到任務後如何完成本地計算並向礦池提交驗證 share。
Stratum 究竟站在挖礦鏈路的哪一段
一台礦機要參與比特幣這類 SHA-256 工作量證明的網絡,手頭得同時握有三份東西:一份已經校驗過、可以合法延伸最長鏈的區塊模板;一個明確的目標值,用來判斷算出來的雜湊是否合格;還有一條能把結果送出去、並讓礦池確認這就是自己那份任務的通道。模板的源頭是比特幣全節點,目標值的源頭是網絡難度,而把這兩者打包、切分、分派給成千上萬台礦機,最後再把分散的算力收攏成一條有效區塊的工作,落在礦池身上。Stratum 協議就是礦池與礦機之間那條通道的規格書。
在 Stratum 出現以前,礦機用的是 getwork。礦機向礦池輪詢一份只有區塊頭的模板,自己填 nonce,找到合格的雜湊就把整份模板送回去。這套做法在 CPU 與 GPU 年代還撐得住,到了 ASIC 時代就撐不住了。單台 ASIC 每秒能丟出上百萬億次雜湊,如果每一次「我還在找」都要靠輪詢去問礦池,頻寬與往返延遲會直接吃掉產出;礦機從拿到模板到礦池換上下一份模板之間的空窗,也會製造大量過期工作。Stratum 把方向反過來:連線建立後長時間保持,礦池一旦有新的模板要分派,就主動推一條通知給礦機,礦機不必再問。它沿用 JSON-RPC 的訊息外形,走純 TCP,每條訊息以換行符結束,沒有 HTTP 標頭那層開銷,一個礦池能撐住的同時連線數量因此高了好幾個數量級。

理解 Stratum,關鍵在於看清楚它在整條鏈路上做的其實是「切分」這件事。區塊模板裡有幾百筆甚至幾千筆交易,這些資料不會全部送到礦機手上;礦機真正需要的,只是一組足以還原 Merkle 根的中間值,加上 coinbase 交易的頭尾兩段。把資料切成這個規模之後,一條 notify 訊息往往只有幾百位元組,礦機在本地重組、雜湊、試算的過程幾乎不佔頻寬。所謂 挖礦模板 Stratum 協議 運作流程,講的就是這套從模板生成、任務切分、下發、本地試算,到提交驗證的完整鏈條。
一條連線是怎麼建立起來的:訂閱、授權與難度設定
礦機與礦池之間的握手由 mining.subscribe 開場。礦池收到後會回覆完整的訂閱參數:包含訂閱識別碼(用於 track notify 與 difficulty 通知)、分配給這條連線的 extranonce1,以及指定礦機可填寫欄位長度的 extranonce2_size。extranonce1 是礦池用來區分不同連線的計數器,長度由礦池自行決定。它會嵌進 coinbase 交易裡面,讓每條連線算出來的 coinbase 都不一樣。這一點不能省略:假如兩台礦機的 coinbase 完全相同,它們的 Merkle 根與區塊頭也會一模一樣,等於在同一段 nonce 空間裡重複做白工,而礦池收到的提交會有大量重複。
握手之後是 mining.authorize,礦機把 worker 名稱(多半是「帳號.礦工名」的格式)與一組密碼送過去。在絕大多數礦池的實作裡,這組密碼只是形式,真正決定收益歸屬的是 worker 名稱。授權通過後,礦池會用 mining.set_difficulty 告訴礦機該按哪個難度去找 share,接著開始以一連串 mining.notify 推送可挖的任務。礦機也可以主動送 mining.suggest_difficulty 表達偏好,不過最終數字由礦池拍板。
想回報型號與韌體版本的礦機會用 mining.configure 或 client.get_version,想追蹤 extranonce 變化的會用 mining.extranonce.subscribe。這些都屬於選配擴充,缺席不影響主流程跑完。
礦池端:從節點模板到可派發的工作包
向全節點索取區塊模板
礦池後端通常掛著一組比特幣全節點,透過 getblocktemplate(BIP22)呼叫取得當前最佳鏈尖之後的候選模板。節點回傳的內容包含可用交易清單(已按手續費密度排序)、上一區塊雜湊、目標值、區塊高度、mintime 與 curtime,以及一個 coinbasevalue,也就是區塊補貼加上所有交易手續費的總額。礦池並不會原封不動照單全收。它多半會設一條手續費門檻,把過於廉價的交易剔出去,換取更小的區塊體積與更快的傳播速度——區塊廣播得慢,被其他礦池搶先一步的機率就上升。這一層決策完全是礦池的商業判斷,礦機完全看不到。
Coinbase 的組裝與切割
coinbase 是區塊裡最特殊的一筆交易。它沒有真正的輸入,輸入欄位放的是一段任意資料,礦池會在這裡塞入區塊高度(BIP34 之後屬於必填)、一段自訂標記,然後把 extranonce 的空間預留出來。Stratum 的做法是把這筆已經序列化完成的 coinbase 交易從中間切成兩截:前半段叫 coinb1,後半段叫 coinb2,切口處留出的空位就是 extranonce1 加上 extranonce2 準備填入的位置。
往後礦機收到的通知裡不會有完整的 coinbase,只有 coinb1 與 coinb2 這兩段十六進位字串。這個切法同時達成兩件事:一是頻寬上的節省,整筆 coinbase 交易不必每次重傳;二是控制權的保留,coinbase 腳本裡寫了什麼、區塊獎勵付給哪個地址,決定權仍牢牢握在礦池手裡。對獨立礦工或想自行指定 coinbase 內容的使用者來說,這是 Stratum V1 最常被抱怨的限制之一。
Merkle 分支的預先計算
模板裡的其餘交易不會下發給礦機。礦池自己把這些交易的 txid 兩兩合併、逐層雜湊上去,直到只剩下連接 coinbase 所需的那幾個兄弟節點,這一串就是 merkle_branch。礦機拿 coinbase 的 txid 當起點,與分支裡的元素依序做雙 SHA-256,就能還原出整棵樹的根。分支長度大約是交易筆數以二為底的對數,一萬筆交易的區塊也不過十幾個 32 位元組字串。礦機為此付出的運算成本近乎為零。

難度與目標值的換算
消息裡的 nbits 是壓縮形式的難度目標,四個位元組裡帶著指數與尾數。這個值對應的是全網難度,也就是真正決定能否產生合法區塊的門檻。礦池不會把這個門檻直接丟給礦機,因為以現在的算力規模,一台礦機可能連續幾天甚至幾個月都碰不到一個合格解,礦池根本無法從提交頻率判斷對面那台機器是否還在運作。實務上,礦池會換算出一組低得多的份額(share)難度,透過 mining.set_difficulty 送給礦機。
mining.notify 的欄位拆解
一條通知訊息是整條流水線的核心。它把礦池手上那份模板壓縮成礦機重組所需的最小集合。
| 欄位 | 內容 | 礦機怎麼用 |
|---|---|---|
| job_id | 礦池自訂的任務編號 | 提交時原樣帶回,礦池靠它找出對應的模板 |
| prevhash | 前一區塊雜湊 | Stratum 送來的 prevhash 已是區塊頭內部位元組序(小端格式),解碼後直接寫入區塊頭。若手頭是大端雜湊才需要反轉。 |
| coinb1 / coinb2 | coinbase 交易的兩段 | 中間補上 extranonce1 與 extranonce2 後雜湊成 txid |
| merkle_branch | 一組 32 位元組雜湊陣列 | 與 coinbase txid 逐層合併,還原 Merkle 根 |
| version | 區塊版本號 | 直接寫進區塊頭的前四個位元組(支持 ASICBoost 版本滾動) |
| nbits | 壓縮難度目標 | 寫入區塊頭,也是全網目標值的來源 |
| ntime | 區塊時間戳 | 寫入區塊頭,在允許範圍內可滾動計算 |
| clean_jobs | 布林旗標 | 為 true 時,礦機應立刻清空當前計算緩存並切換至新任務 |
clean_jobs 這個旗標值得單獨說明。當礦池發現鏈尖已經被網絡上其他礦池延伸、或者自己決定換一組高手續費交易時,它會推送新任務並把 clean_jobs 設為 true。礦機收到後如果還在舊任務上算,算出來的東西即使達到 share 標準也無法變成有效區塊。這種提交稱為過期份額(stale share),多數礦池會對過期份額給予較低權重或直接拒絕,具體計算規則需參考各礦池的結算條款。
礦機端收到任務之後做了什麼:本地試算與提交驗證
當礦機接收到 mining.notify 後,硬體晶片與控制單元會依照以下步驟完成數據拼裝與暴力求解:
-
拼裝 Coinbase 交易:礦機選定一個尚未重複的
extranonce2(長度為握手時取得的 extranonce2_size),將其拼接在coinb1與coinb2中間,即:Coinbase = coinb1 + extranonce1 + extranonce2 + coinb2。隨後對整筆數據進行雙重 SHA-256 哈希,計算出這筆 coinbase 的交易 ID(txid)。 -
還原 Merkle 根:以剛算出的 coinbase txid 為起點,與
merkle_branch陣列中的各個節點依次兩兩串接並做雙 SHA-256 計算,最終得到該區塊候選體的 Merkle Root。 -
構建 80 位元組區塊頭(Block Header):按標準格式組裝區塊頭,順序為:
- 4 bytes: version(版本號)
- 32 bytes: prevhash(前一區塊雜湊)
- 32 bytes: merkle_root(Merkle 根)
- 4 bytes: ntime(當前時間戳)
- 4 bytes: nbits(壓縮目標值)
- 4 bytes: nonce(隨機數起點)
-
算力晶片高速哈希試算:ASIC 晶片開始在 32 位元的 nonce 空間(0x00000000 至 0xFFFFFFFF)內不斷遞增並進行雙 SHA-256 計算。若 32 位元空間耗盡仍未找到符合要求的雜湊,礦機可透過遞增
extranonce2或微調ntime(在允許的時間漂移範圍內)重新計算 Merkle root,進而獲取全新的 nonce 試算空間。 -
Share 判定與提交:礦機每算出一個雜湊結果,都會將其與礦池下發的 share 難度目標 進行比對。只要雜湊值小於等於 share 目標,即便尚未達到全網目標(Network Target),礦機也會立即向礦池發送
mining.submit訊息提交成果。
礦池端校驗與結果反饋
當礦池接收到礦機發來的 mining.submit 請求時,並不會盲目信任礦機提交的數據。礦池會在伺服器端執行相應的輕量級驗證流程:
- 根據提交訊息中的
job_id檢索歷史任務模板,確認該任務依然處於有效期內(非嚴重過期的任務)。 - 取出礦機提交的
extranonce2、ntime與nonce,使用相同的演算法重組區塊頭。 - 對重組後的區塊頭進行雙 SHA-256 雜湊計算,檢查其結果是否確實小於分配給該礦機的 share 難度。
驗證通過後,礦池會在 JSON-RPC 回覆中返回 "result": true,代表該次工作量已被認可並計入礦工的算力貢獻中;若驗證失敗(例如哈希不合規、任務已作廢或重複提交),則回覆 "result": false 並附加錯誤碼。
倘若礦池驗證時發現某個 share 的雜湊值不僅達到了 share 難度,甚至低於比特幣全網絡當前的 nbits 目標值,這意味著該礦機成功幸運地解出了全網有效區塊!礦池會立即拼裝出完整的區塊數據,並通過 P2P 網絡向全球比特幣全節點廣播,為礦池贏得區塊獎勵與交易手續費。
技術協議版本:Stratum V1 (BIP22 / BIP34 擴充規範)
參考標準文檔:Slush Pool Stratum Mining Protocol Specification, Bitcoin Developer Reference.
常見問題 FAQ
Q1:Stratum V1 協議主要存在哪些局限性?
Stratum V1 使用明文 JSON-RPC 傳輸,缺乏原生加密與身份驗證機制,容易遭受中間人攻擊(MITM)或算力劫持。此外,礦機無法自主選擇包含在區塊中的交易,所有交易模板均由礦池掌控,這在一定程度上削弱了區塊鏈的去中心化特性。
Q2:新一代 Stratum V2 協議進行了哪些實質性改進?
Stratum V2 引進了基於 Noise 通信協定的二進位加密傳輸,顯著降低頻寬消耗並防止中間人攻擊;同時引入了「作業協商(Job Negotiation)」機制,允許礦工自訂區塊交易模板,進一步提升了採礦生態的安全性與去中心化程度。
Q3:為何礦機需要動態調整 Extranonce2 與 Ntime?
區塊頭中的 32 位元 nonce 欄位僅提供約 42.9 億次組合,在高算力 ASIC 礦機上不到一毫秒就會被遍歷完畢。透過擴展 extranonce2(修改 coinbase 交易)或微調 ntime(時間戳),礦機可以在不頻繁請求新任務的前提下,不斷生成全新的 Merkle root 與區塊頭,從而開闢出無限的算力搜尋空間。



