scrypt Stratum-client 的完整範例數據
我正在嘗試使用 Stratum Communication 為基於 Scrypt 的探勘編寫一個探勘客戶端。到目前為止,我在驗證所有位順序和序列時遇到了一些麻煩。由於未達到目標,我生成的雜湊總是被拒絕。
我正在尋找的是完整的數據序列,從我從地層伺服器(coinbases,merkles,…)獲得的資訊開始,到最終的雜湊。
我已經可以驗證算法的某些部分(主要是從輸入到有效的 merkle-root,使用http://mining.bitcoin.cz/stratum-mining/的資訊和 scrypt 散列,使用來自https的塊頭: //litecoin.info/Scrypt),但我猜兩者之間存在一些字節序問題,或者完全不同的東西,我不知道……通過完整的工作流程,我可以驗證錯誤發生的位置。
有誰知道從哪裡獲得這些數據,或者如何為自己生成它們?
好吧,我終於設法修復了我的錯誤並獲得了完整的往返。這是一個與池進行完全通信的範例。我不會詳細解釋所有內容,因為 API 描述可以在其他地方找到。
a) 訂閱
{"id": 1, "method": "mining.subscribe", "params": []} {"error": null, "id": 1, "result": [["mining.notify", "ae6812eb4cd7735a302a8a9dd95cf71f"], "f8002c90", 4]}
我們向伺服器訂閱。這沒有參數。結果,我們收到了一些訂閱 ID,以及我們的 Extranonce1 + extranonce2 大小,我們稍後需要。b) 授權
{"params": ["User", "password"], "id": 2, "method": "mining.authorize"} {"error": null, "id": 2, "result": true}
使用使用者名 + 密碼授權工作人員。結果中沒有要儲存的參數。c) 伺服器 -> 難度
{"params": [32], "id": null, "method": "mining.set_difficulty"}
將難度設置為 32,定義我們的目標。由此產生的難度可以計算為
0x0000FFFF00000000000000000000000000000000000000000000000000000000 / 32 = 0x000007fff8000000000000000000000000000000000000000000000000000000
現在,有趣的部分:d)阻止資訊
{"params": ["b3ba", "7dcf1304b04e79024066cd9481aa464e2fe17966e19edf6f33970e1fe0b60277", "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff270362f401062f503253482f049b8f175308", "0d2f7374726174756d506f6f6c2f000000000100868591052100001976a91431482118f1d7504daf1c001cbfaf91ad580d176d88ac00000000", ["57351e8569cb9d036187a79fd1844fd930c1309efcd16c46af9bb9713b6ee734", "936ab9c33420f187acae660fcdb07ffdffa081273674f0f41e6ecc1347451d23"], "00000002", "1b44dfdb", "53178f9b", true], "id": null, "method": "mining.notify"}
我拆分參數並將它們分配給變數
job_id = "b3ba" prevhash = "7dcf1304b04e79024066cd9481aa464e2fe17966e19edf6f33970e1fe0b60277" coinb1 = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff270362f401062f503253482f049b8f175308" coinb2 = "0d2f7374726174756d506f6f6c2f000000000100868591052100001976a91431482118f1d7504daf1c001cbfaf91ad580d176d88ac00000000" Merklebranches = [ "57351e8569cb9d036187a79fd1844fd930c1309efcd16c46af9bb9713b6ee734", "936ab9c33420f187acae660fcdb07ffdffa081273674f0f41e6ecc1347451d23" ] version = "00000002" nbits = "1b44dfdb" ntime = "53178f9b" clean_jobs = true// Not required for block, just for completeness
我們還需要 extranonce1 和 extranonce 2:
extranonce1 = "f8002c90" // from earlier extranonce2 = "00000002" // can be anything, but 4 bytes
有了這個,我們可以開始建構我們的 Merkle 根:首先,coinbase:
coinbase = coinb1 + extranonce1 + extranonce2 + coinb2; coinbase = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff270362f401062f503253482f049b8f175308f8002c90000000020d2f7374726174756d506f6f6c2f000000000100868591052100001976a91431482118f1d7504daf1c001cbfaf91ad580d176d88ac00000000"
現在,我們將這個 coinbase 轉換為二進制。無需翻轉或 BE-LE 轉換,直接從左到右。生成的二進制數據使用 sha256(sha256(data)) 進行雜湊處理。從這裡開始,我將二進制發佈為十六進製表示,但原樣:從左到右,沒有字節序轉換
resulting hash : 280b3927f6763b1ed90cae2a3cef4d27c743f6a7d91e3901dc3816a46acacf36
這是 merkle 連接的開始。連接意味著只是加入他們。32 字節的散列和 32 字節的每個 merkleroot 導致 64 字節的數據要散列。
for each Merkle_branch byte[64] = hash + merkle_branch hash = sha256(sha256(byte)) end
例如,它看起來像這樣:
byte = 280b3927f6763b1ed90cae2a3cef4d27c743f6a7d91e3901dc3816a46acacf36 + 57351e8569cb9d036187a79fd1844fd930c1309efcd16c46af9bb9713b6ee734 hash = e6df228610b9f0e96a42a4877565627a3e1e133e984b6c46ff6e44b7dc9dc056 byte = e6df228610b9f0e96a42a4877565627a3e1e133e984b6c46ff6e44b7dc9dc056 + 936ab9c33420f187acae660fcdb07ffdffa081273674f0f41e6ecc1347451d23 hash = 0b1edc1ccf82d3214423fc68234f4946119e39df2cc2137e31ebc186191d5422
這是最終的 merkle_root。不需要再轉回十六進制,可以保存為二進制格式,以備下一步使用
e) 區塊頭 區塊頭是使用所有先前的資訊 + 計算的默克爾根建構的。它產生 80 字節的數據
blockHeader { version[4] prevhash[32] merkle_root[32] ntime[4] nbit[4] nonce[4] }
在這裡,字節順序有點棘手:所有 4 字節類型都是小端,並且必須翻轉字節。Merkleroot 可以 1:1 複製,無需翻轉字節。prevhash 是最讓我驚訝的。最好將其視為 8 個 4 字節整數的數組,其中每個整數都必須轉換為 LE,但順序保持從左到右。我在範例中顯示它:
version: 00000002 --> 02000000 prevhash: 7dcf1304 b04e7902 4066cd94 81aa464e 2fe17966 e19edf6f 33970e1f e0b60277 --> 0413cf7d 02794eb0 94cd6640 4e46aa81 6679e12f 6fdf9ee1 1f0e9733 7702b6e0 // 8 ints left to right, each one flipped merkle: 0b1edc1c cf82d321 4423fc68 234f4946 119e39df 2cc2137e 31ebc186 191d5422 // nothing changed ntime: 53178f9b --> 9b8f1753 nbits: 1b44dfdb --> dbdf441b
產生以下字節流:
020000000413cf7d02794eb094cd66404e46aa816679e12f6fdf9ee11f0e97337702b6e00b1edc1ccf82d3214423fc68234f4946119e39df2cc2137e31ebc186191d54229b8f1753dbdf441b00000000
請注意,我們不需要填充或任何東西,就像比特幣實現一樣,我們只需要 80 個字節。現在,讓我們對其進行散列 f) 散列和結果通過 scrypt 循環發送它會產生以下散列:
f6f13e350aa4f251e192ab8a78690ee99f1cc2d930d4ae16c4172a0a8aefddd0
嗯,這不是我們要找的雜湊……所以我們先玩隨機數,如果這還不夠,我們可以增加 ntime。直到最後,經過很長時間,我們嘗試
nonce = "00007f8a" // BigEndian time = "53178f9f" // BigEndian
這為我們提供了以下塊和結果雜湊:
block = 020000000413cf7d02794eb094cd66404e46aa816679e12f6fdf9ee11f0e97337702b6e00b1edc1ccf82d3214423fc68234f4946119e39df2cc2137e31ebc186191d54229f8f1753dbdf441b8a7f0000 hash = 7441207b6390054623bc5e659ffe2581356dafc5ec41db44d27de85035000000
看起來有點高,但在這裡,必須再次考慮字節序。要將其與我們的目標進行比較,我們必須從高到低進行比較。而且,不要忘記我們必須更改目標的字節順序:
target = 0x000007fff8000000000000000000000000000000000000000000000000000000 ---> 0x000000000000000000000000000000000000000000000000000000f8ff070000
現在,如果我們比較它們:
000000000000000000000000000000000000000000000000000000f8ff070000 7441207b6390054623bc5e659ffe2581356dafc5ec41db44d27de85035000000
我們看到雜湊低於我們的目標,我們可以送出它。或者,我們可以以其他字節順序查看它們(大部分時間都以這種順序列印)
000007fff8000000000000000000000000000000000000000000000000000000 0000003550e87dd244db41ecc5af6d358125fe9f655ebc23460590637b204174
大部分看起來都一樣。這導致我們進入最後一步: g) 送出共享 現在我們收集我們使用的可變參數,並將它們發送到伺服器。
user = "user" job_id = "b3ba" extranonce2 = "00000002" // No byte swapping needed. Its how we put it in the coinbase ntime = "53178f9f" // This is Big Endian. The ntime in the block_header is little endian. IF you read it from your block_header, don't forget to swap nonce = "00007f8a" // Same here. Convert To BigEndian before sending
我們將這些數據打包在一個簡潔的 JSon 包裝器中,並將其發送到伺服器:
{"params": ["User", "b3ba", "00000002", "53178f9f", "00007f8a"], "id": 4, "method": "mining.submit"}
而且,如果一切正常,並且我們沒有其他問題(如過期股份或其他任何問題),我們會得到積極的回應:
{"error": null, "id": 4, "result": true}
就是這樣!如需更多分享,請根據需要重複多次。