Scrypt

scrypt Stratum-client 的完整範例數據

  • January 19, 2021

我正在嘗試使用 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}

就是這樣!如需更多分享,請根據需要重複多次。

引用自:https://bitcoin.stackexchange.com/questions/22929