revision of this document: R2
- I. Introduction 簡介
- II. Concept 概念
- III. Specifications (RFC) 規范(RFC)
- IV. Real world scenario 真實場景
- V. Planned improvements 增強計劃
- VI. Contact 聯系方式
I. 簡介
以太坊沒有正式的stratum協議。它只支持GetWork,這是一個非常耗資源的問題,因為礦工需要不斷的投票來獲得可能的新工作。因此,GetWork會影響到礦工和礦池的性能。由于需要更專業的以太坊挖礦,出現了幾個專為以太坊的“stratum”版本。這些“stratums”利用了服務器端(礦池端)的GetWork來獲取工作,如果創建此類協議時采取仔細考慮因素和預防措施,這將是很好的。但這并沒有完成。這些協議有以下問題:
- 每個礦工/工人都沒有唯一的數據。Extranonce被忽略(但仍然被發送)。每一個礦工都獲取seedhash(每30k塊都是相同的)和headerhash(每個塊都改變)。然后礦工使用這兩個值和自己的Nonce來生成哈希。礦工可能在做重復的工作(如果他們選擇了相同的Nonce)。
- 難度冗余。難度在mining.notify消息中作為已命名目標的第三個參數被發送。這是不需要的,因為礦工們可以通過自己的困難來計算目標哈希。
- 整體數據冗余。有幾個字段不需要通過網絡發送。首先, 如果未使用extranonce,則不必發送。其次,每隔30k個塊更換一次seedhash,就沒有必要每次挖礦都發送。第三,正如在第2條中指出的 - 當使用set_difficulty時, 在mining.notify中的目標是多余的。第四,mining.submit實際上只需要發送一次。礦池需要驗證Nonce的有效性,并將計算哈希和混合哈希(mixhash)。如果刪除所有提及的冗余,可以很容易地減少50%以上的帶寬使用。
- 與原有slush的stratum規范相比,有一些不一致的地方。其中一個是ids。Ids應該增加,以便礦池能夠跟蹤接收到的數據。另一件事是HEX標記'0x'從每個字符串字段開始。這也是多余的,如果不使用的話,我們將節省一些帶寬。
- 沒有規范,只有有實現的解決方案項目。這通常會導致幾個類似的協議版本;到底發生了什么。
我們的目標是建立一個可靠的、無冗余的、刀槍不入的以太坊stratum挖礦協議, 它沒有前面指出的這些問題。
II. 概念
以太坊的GetWork給我們3個值:
{ ... "result":[
"0x645cf20198c2f3861e947d4f67e3ab63b7b2e24dcc9095bd9123e7b33371f6cc",
"0xabad8f99f3918bf903c6a909d9bbc0fdfa5a2f4b9cb1196175ec825c6610126c",
"0x0000000394427b08175efa9a9eb59b9123e2969bf19bf272b20787ed022fbe6c"
]}
第一個值是headerhash,第二個是seedhash, 第三個是目標。 Seedhash用于識別DAG文件, headerhash和64為Nonce由我們的礦機給我們的哈希選擇出, 如果低于提供的目標,則提供塊/共享。
由于Nonce的寬度為64位(8字節),并且考慮到非常糟糕的可能情況,以太坊在5分鐘內沒有發現一個塊,8個字節的Nonce能夠提升礦機的速度到:
(2^64 / 300) / 1G ~ 61,489,147 GH/s
這是一個非常大的數字,所以我們可以很容易地考慮為我們的stratum協議拿走一些字節。
---------------------------------------
| Bytes | Max supported hashing speed |
| 8 | ~61,489,147.000 GH/s |
| 7 | ~240,192.000 GH/s |
| 6 | ~938.000 GH/s |
| 5 | ~3.665 GH/s |
| 4 | ~0.014 GH/s |
---------------------------------------
只有4個字節的Nonce不是一個選項,因為我們已經有了能夠達到14 MH/s以上的礦工。5個字節的Nonce寬度允許最大速度為3.665 GH/s,在相當長的時間內是足夠的,即使ASICs到達。
礦工需要在礦池中得到seedhash、headerhash、難度和部分nonce(被稱為extranonce)。礦工選擇了它自己的第二部分(稱為minernonce)。Extranonce與minernonce連接,它提供64位的Ethereum nonce。
III. 規范(RFC)
在礦工到礦池建立TCP連接之后,就會發生握手。礦工首先發送數據:
{
"id": 1,
"method": "mining.subscribe",
"params": [
"MinerName/1.0.0", "EthereumStratum/1.0.0"
]
}
第一個參數是礦工名稱和版本(正如標準stratum協議)。第二個參數必須是“Ethereum Stratum/Version”,版本是根據該文檔的版本使用的EthereumStratum礦工的版本。如果礦池不支持此版本,它可以終止連接或返回錯誤。
注意,礦工可以迭代ids,可以從任何數字開始。從礦工到礦池的每條消息都需要有唯一的id給礦工以正確讀取響應,因為礦池可能不以FIFO方式處理礦工的消息。
服務器回復:
{
"id": 1,
"result": [
[
"mining.notify",
"ae6812eb4cd7735a302a8a9dd95cf71f",
"EthereumStratum/1.0.0"
],
"080c"
],
"error": null
}
響應幾乎與標準stratum協議具有以下差異;結果數組的第一個參數的第三個參數為“EthereumStratum/Version”;如果礦池沒有報告此參數或版本與礦工支持的不同,礦工可以預期兼容性問題,并終止連接。結果數組的第二個參數是由礦池設置的extranonce(在十六進制中)。沒有第三個參數,因為沒有extranonce2(正如標準stratum)。Extranonce可能最大3字節。
礦工應在初次握手時授權;這與標準stratum協議相同,在這里將不會詳細解釋。
在第一份任務(工作)提供之前,礦池必須通過發送設置難度:
{
"id": null,
"method": "mining.set_difficulty",
"params": [
0.5
]
}
參數數組的第一項是雙重數據類型的難度。難度和目標之間的轉換與比特幣一樣;難度1轉化為HEX的目標:
00000000ffff0000000000000000000000000000000000000000000000000000
如果礦池在第一份工作之前沒有設置難度,那么礦工就可以假定難度是1。
當難度發生變化時,礦工們開始為每一份到達的NEXT任務使用新的難度。
如果礦工已經訂閱extranonce通知(詳細解釋在這里:https://www.nicehash.com/?p=software#devs),然后礦池可能會改變礦工的extranonce通過發送:
{
"id": null,
"method": "mining.set_extranonce",
"params": [
"af4c"
]
}
新的extranonce對于所有在礦池中發送的NEXT任務都有效。
礦池通過發送以下數據通知礦工工作(工作):
{
"id": null,
"method": "mining.notify",
"params": [
"bf0488aa",
"abad8f99f3918bf903c6a909d9bbc0fdfa5a2f4b9cb1196175ec825c6610126c",
"645cf20198c2f3861e947d4f67e3ab63b7b2e24dcc9095bd9123e7b33371f6cc",
true
]
}
參數數組的第一個參數是任務ID(必須是任意大小的十六進制數)。第二個參數是seedhash。每一個任務都發送一個seedhash來支持盡可能多的礦池,這可能會很快地在貨幣之間交換。第三個參數是headerhash。最后一個參數是boolean cleanjobs。如果設為true,那么礦工需要清理任務隊列,并立即開始從事新提供的任務,因為所有舊的任務分享都將導致陳舊的分享錯誤。
礦工使用seedhash識別DAG,然后試著帶著headerhash,extranonce和自己的minernonce尋找低于目標的分享(這是由提供的難度而產生的)。
當發現低于目標的分享時,礦工將其提交給礦池:
{
"id": 244,
"method": "mining.submit",
"params": [
"username",
"bf0488aa",
"6a909d9bbc0f"
]
}
參數數組的第二個參數是任務ID,第三個參數是minernonce。注意在上面的例子中,minernonce是6個字節,因為提供的extranonce是2個字節。如果礦池提供3字節的extranonce,那么minernonce必須是5字節。
對于每一個提交的工作,礦池需要返回標準stratum響應:
{
"id": 244,
"result": true,
"error": null
}
或者如果分享不被接受(標準stratum響應):
{
"id": 244,
"result": false,
"error": [
-1,
"Job not found",
NULL
]
}
IV. 真實場景
礦工連接礦池并發送:
{
"id": 1,
"method": "mining.subscribe",
"params": [
"EthereumMiner/1.0.0", "EthereumStratum/1.0.0"
]
}
礦池響應:
{
"id": 1,
"result": [
[
"mining.notify",
"ae6812eb4cd7735a302a8a9dd95cf71f",
"EthereumStratum/1.0.0"
],
"a2eea0"
],
"error": null
}
礦工然后認證:
{
"id": 2,
"method": "mining.authorize",
"params": [
"test",
"password"
]
}
礦池確認:
{
"id": 2,
"result": true,
"error": null
}\n
礦池發送難度:
{
"id": null,
"method": "mining.set_difficulty",
"params": [
1.0
]
}\n
然后任務:
{
"id": null,
"method": "mining.notify",
"params": [
"bf0488aa",
"abad8f99f3918bf903c6a909d9bbc0fdfa5a2f4b9cb1196175ec825c6610126c",
"fc12eb20c58158071c956316cdcd12a22dd8bf126ac4aee559f0ffe4df11f279",
true
]
}\n
過了一段時間,礦工找到了分享并提交:
{
"id": 3,
"method": "mining.submit",
"params": [
"test",
"bf0488aa",
"cfae7df760"
]
}\n
礦池響應:
{
"id": 3,
"result": true,
"error": null
}\n
分享是有效考慮數據:
seedhash=abad8f99f3918bf903c6a909d9bbc0fdfa5a2f4b9cb1196175ec825c6610126c
headerhash=fc12eb20c58158071c956316cdcd12a22dd8bf126ac4aee559f0ffe4df11f279
nonce=a2eea0cfae7df760
結果是難度的1.863, 大于1.0.
V. 增強計劃
以太坊有RPC方法eth_getBlockByNumber,它可以返回一些尚未被挖掘的下塊數據。數據中有下一個塊號(塊高度)。這個數字可以代替seedhash;然后,每個礦工都將計算自己的seedhash,因此帶寬的使用將會減少更多。
有一些改造eth_getBlockTemplate方法的計劃。當這種情況發生時,這種stratum協議可能與標準stratum非常相似。