使用 Python 從 block_number 和種子生成記憶體
我正在嘗試從此處提供的 Python 程式碼執行 Ethash 算法: https ://eth.wiki/concepts/ethash/ethash ,並且在將生成的記憶體文件與真實的記憶體文件進行比較時遇到了一些麻煩網路,由geth執行。
作為第一步,我從給定的 block_number 和種子生成一個記憶體文件。記憶體生成算法在
mkcache(cache_size, seed)
上面連結的相應函式中進行了描述。執行該函式後,我得到了 16x995326 列表,每個元素中都有 32 位整數。在將此列表序列化為二進製文件(使用 Python
struct
模組)後,我得到了一個 61 兆字節的文件。現在,問題是:如何驗證生成的記憶體文件實際上是正確的,並且在目前的乙太坊網路中是完整的?大家對此有什麼想法嗎?
我現在進行此驗證的方式是將我的記憶體文件與 geth 執行的實際乙太坊節點的記憶體文件進行比較。
例如:
- 讓我們取一個塊號:10757149
- 對於這個區塊號,我們可以得到對應的種子(請檢查種子是否正確):0xf7f6e04564e6b37fb9017324dc2577bd24cd25977037cfe8cd95b590009e2391
- 從執行 geth 的完全同步的乙太坊節點,我可以找到實際的記憶體文件,位於 .ethereum/geth/ethash/cache-R23-f7f6e04564e6b37f
- 在該記憶體文件上執行 md5sum,我得到以下校驗和:d767fc7d317c78c6ac2e8b0a111d5dc0(順便說一句,如果您正在執行完全同步的 geth,您應該為 R23-f7f6e04564e6b37f 記憶體獲得相同的 md5hash)
現在,給定 block_number 和種子,我正在執行上面連結中範例中的 Python 腳本,並且我的記憶體文件上的 md5sum 不同!
在那一點上,我真的很困惑,到目前為止不知道如何檢查記憶體文件的正確性。其他一些問題出現在我的腦海中,也許你可以澄清一些事情:
- eth.wiki/concepts/ethash/ethash中的算法實際上是否遵循了乙太坊(geth)的官方實施?
- 查看 geth 的原始碼,我懷疑記憶體生成算法是不同的。我不擅長解析 go-syntax,所以也許你們中的一些人可以
mkcache
從這裡檢查函式的 Python 版本:eth.wiki/concepts/ethash/ethash,以及來自 geth 的相應函式:github。 com/ethereum/go-ethereum/blob/master/consensus/ethash/algorithm.go#L139。如果有人能看到算法中的實際差異(如果存在的話),我會很高興。- 可能是由於記憶體序列化的差異(當生成的數組被寫入文件時)?
非常感謝有關該主題的任何提示。你可以在這裡找到我正在使用的 Python2.7 腳本:github.com/dugdmitry/ethash_python/blob/master/run_miner.py
謝謝!
剛剛解決了問題。
mkcache
在實現上面範例中的函式時,我犯了幾個錯誤:
0xf7f6e04564e6b37fb9017324dc2577bd24cd25977037cfe8cd95b590009e2391
block_number的種子10757149
不正確。從給定的塊號計算種子的正確方法是通過以下函式:def get_seedhash(block_number): s = '\x00' * 32 for i in range(block_number // EPOCH_LENGTH): s = serialize_hash(sha3_256(s)) return s
- 此處eth.wiki/concepts/ethash/ethash的 eth-wiki 中的
sha3.sha3_256()
和散列函式不正確(或者說已經過時)。從閱讀原始碼可以看出,使用了以下散列函式:和. 這些函式在Python模組中提供。因此,函式的更正程式碼如下所示:sha3.sha3_512()``geth``sha3.keccak_256()``sha3.keccak_512()``pysha3
mkcache
def serialize_hash(h): return ''.join([zpad(encode_int(x), 4) for x in h]) def deserialize_hash(h): return [decode_int(h[i:i+WORD_BYTES]) for i in range(0, len(h), WORD_BYTES)] def hash_words(h, sz, x): if isinstance(x, list): x = serialize_hash(x) y = h(x) return deserialize_hash(y) # sha3 hash function, outputs 64 bytes def sha3_512(x): return hash_words(lambda v: sha3.keccak_512(v).digest(), 64, x) # Generate cache def mkcache(cache_size, seed): n = cache_size // HASH_BYTES # Sequentially produce the initial dataset o = [sha3_512(seed)] for i in range(1, n): o.append(sha3_512(o[-1])) # Use a low-round version of randmemohash for _ in range(CACHE_ROUNDS): for i in range(n): v = o[i][0] % n o[i] = sha3_512(map(xor, o[(i-1+n) % n], o[v])) return o
- 此外,當計算的記憶體被序列化到文件中時,
0xfee1deadbaddcafe
應該在該文件前添加一個特殊字節。進行這些更改後,我能夠生成一個正確的記憶體文件,該文件與對應的記憶體文件
md5sum
相匹配,由一個真實的、完全同步的節點上的同一塊生成。都好。md5sum``geth
希望它對某人有幫助。
使用 keccak 算法,對於 block_number 10757149 的種子雜湊“0xf7f6e04564e6b37fb9017324dc2577bd24cd25977037cfe8cd95b590009e2391 是正確的。我已經用 python 和 goeth 對其進行了測試。
感謝這次問答,我還使用了錯誤的雜湊算法:sha3_256 在 python 範例和 goeth 之間生成兩個不同的種子雜湊。並花了幾個小時找出問題所在。