礦池運營商如何進行雜湊處理?
對於池服務的每個“getwork”,必須為一個塊計算一個 Merkle 根。SHA-256 的執行時間與 256 位“塊”的數量成正比,一個典型的塊將有數千個這樣的塊(在預處理之後,塊頭只有三個)。因此,礦池運營商將需要大致在 Mhash/sec 範圍內的散列能力。到目前為止我是對的嗎?
單個礦工需要更多的散列能力,但形式更簡單:這是一個三塊預處理的塊頭;在 nonce 欄位中使用 0000_0000x 到 FFFF_FFFFx 中的每一個對其進行散列。如果散列引擎專注於這種簡單性,以使它們更便宜和/或更快,那麼它們對於礦池運營商來說就不那麼好用了。
因此,如果我是礦池運營商或獨立礦工,並且需要生成數百萬個 Merkle 根,我的選擇是什麼?雜湊引擎(CPU/GPU/FPGA/ASIC)是否有我可以使用的 API?
礦池通常會為礦工的每個 getwork 請求創建一個唯一的 merkle 根。如果它接受難度 1 份額,礦工可以在該區塊上平均花費大約 4,000 兆雜湊(並且平均每個 getwork 將獲得 1 份額)。
為了為每個礦工創建一個區塊頭,礦池運營商在區塊的第一(代)交易中更改一些唯一資訊,然後重新散列該區塊以創建默克爾根。如果天真地完成,這將需要 O(N log N) sha256 雜湊(其中 N 是正在探勘的塊中的事務數)。通過從計算最後一個 merkle 根中保存一些資訊,您可以僅使用 O(log N) 雜湊重新計算生成事務中的更改。
每個區塊有數百筆交易,礦池運營商和礦工執行的雜湊比率超過 1 億比 1。
為了更大的節省,池可以接受 getblocktemplate api 請求而不是 getwork 請求。這種模式允許礦工生成自己的區塊頭並平均開採 10 分鐘,然後才需要被礦池刷新。
伺服器工作的一個計算密集型部分是創建新的默克爾根。正如 mckoss 所提到的,如果您只重新計算由新一代事務更改的 merkle 分支,而不是重新計算整個 merkle 樹,這會變得更快。
伺服器工作的另一個計算密集型部分是驗證稍後發送的工作證明。通常這意味著散列兩個 SHA-256 塊並根據難度驗證結果。但是,如果有多個具有相同 merkle 根的工作證明,那麼您可以計算一次中間狀態,然後為您要驗證的每個工作證明散列一個 SHA-256 塊。就像客戶對 rollntime 所做的那樣。
因此,每一個新的默克爾根都是要生成的,並且在以後需要計算一個新的中間狀態來創建更多的工作。
BitMinter 在伺服器和客戶端都使用滾動 ntime 欄位。每次掛鐘向前滴答一秒,您都會使用新的時間戳更新塊數據的 ntime 欄位。然後,您可以重用前一秒的所有 merkle 根和中間狀態。
這可以節省伺服器上的大量工作,這就是 BitMinter 可以在具有 2-3 TH/s 雜湊能力的單個伺服器上以低負載執行的方式,而一些(沒有很好優化的)池需要每 300 GH 的新伺服器/s 的算力。
從那時起,這種優化變得不那麼重要了。更多客戶開始支持 rollntime。伺服器和客戶端開始使用高於 1 的工作難度,這意味著需要在伺服器上驗證的工作要少得多。然後有新的協議來取代 getwork:Stratum 和 GBT (getblocktemplate)。使用這些協議,伺服器只生成一個生成起來非常便宜的模板,然後客戶端根據模板完成創建工作的大部分工作。
我仍然認為客戶端使用 ntime 技巧重用 merkle 根和中間狀態是一個好主意,這也允許在伺服器端重用中間狀態,儘管這不再是什麼大問題。