以太坊原始碼分析 Ethash共識演算法

2021-08-21 10:47:52 字數 3866 閱讀 2476

ethereum當前和bitcoin一樣,採用基於工作量證明(proof of work,pow)的共識演算法來產生新的區塊。與bitcoin不同的是,ethereum採用的共識演算法可以抵禦asic礦機對挖礦工作的壟斷地位,這個演算法叫做ethash

為什麼要反asic

pow的的核心是hash運算,誰的hash運算更快,誰就更有可能挖掘出新的區塊,獲得更多的經濟利益。在bitcoin的發展過程中,挖礦裝置經歷了(cpu=>gpu=>asic)的進化過程,其中的動機就是為了更快地進行hash運算。隨著礦機門檻地提高,參與者久越來越少,這與區塊鏈的去中心化構想背道而馳。

因此,在共識演算法設計時,為了減少asic礦機的優勢(專用平行計算),ethereum增加了對於記憶體的要求,即在進行挖礦的過程中,需要占用消耗大量的記憶體空間,而這是asic礦機不具備的(配置符合運算那能力的記憶體太貴了,即使配置,這也就等同於大量cpu了)。即將挖礦演算法從cpu密集型(cpu bound)轉化為io密集型(i/o bound)

dagger-hashimoto

ethash是從dagger-hashimoto演算法改動而來的,而dagger-hashimoto的原型是thaddeus dryja提出的hashimoto演算法,它在傳統bitcoin的工作量證明的基礎上增加了消耗記憶體的步驟。

傳統的pow的本質是不斷嘗試不同的nonce,計算hash ha

sh_o

utpu

t=ha

sh(p

rev_

hash

,mer

kler

oot,

nonc

e)h as

h_ou

tput

=has

h(pr

ev_h

ash,

merk

lero

ot,n

once

)如果計算結果滿足ha

sh_o

utpu

trget

h as

h_ou

tput

rget

,則說明計算的nonce是有效的

而對於hashimoto,hash運算僅僅是第一步,其演算法如下:

nonce:
64-bits.正在嘗試的nonce值

get_txid(t):歷史區塊上的交易t的hash

total_transactions: 歷史上的所有交易的個數for i = 0

to63 do

shifted_a = hash_output_a >> i

transaction = shifted_a mod total_transactions

txid[i] = get_txit(transaction) << i

endof

txid_mix = txid[0]^txid[1]...txid[63]

final_output = txid_mix ^ (nonce<<192)

可以看出,在進行了hash運算後,還需要進行64輪的混淆(mix)運算,而混淆的源資料是區塊鏈上的歷史交易,礦工節點在執行此演算法時,需要訪問記憶體中的歷史交易資訊(這是記憶體消耗的**),最終只有當 fi

nal_

outp

utrget

f in

al_o

utpu

trget

時,才算是找到了有效的nonce

dagger-hashimoto相比於hashimoto,不同點在於混淆運算的資料來源不是區塊鏈上的歷史交易,而是以特定演算法生成的約1gb大小的資料集合(dataset),礦工節點在挖礦時,需要將這1gb資料全部載入記憶體。

ethash演算法概要

ethash原始碼解析

dataset生成

dataset通過generate()方法生成,首先是生成cache,再從cache生成dataset

挖礦(seal)

在挖礦與共識中提到了,共識演算法通過實現engine.seal介面,來實現挖礦,ethash演算法也不例外。

其頂層流程如下:

}hashmotofull()是運算的核心,內部呼叫hashmoto(),第三個引數為dataset的大小(即1gb),第四個引數是乙個lookup函式,它接收index引數,返回dataset中64位元組的資料。

func hashimoto(hash byte, nonce uint64, size uint64, lookup func(index uint32) uint32) (byte, byte) 

temp := make(uint32, len(mix))

// 進行總共loopaccesses=64輪的混淆計算,每次計算會去dataset裡查詢資料

for i :=0; i < loopaccesses; i++

fnvhash(mix, temp)

}// 壓縮mix:將32個uint32的mix壓縮成8個uint32

for i :=0; i < len(mix); i +=4

mix = mix[:len(mix)/4]

// 用8個uint32的mix填充32位元組的digest

digest := make(byte, common.hashlength)

for i, val := range mix

// 對seed+digest計算hash,得到最終的hash值

}

驗證(verify)

驗證時verifyseal()呼叫hashimotolight()light表明驗證者不需要完整的dataset,它需要用到的dataset中的資料都是臨時從cache中計算。

func hashimotolight(size uint64, cache uint32, hash byte, nonce uint64) (byte, byte) 

return data

}return hashimoto(hash, nonce, size, lookup)

}

除了lookup函式不同,其餘部分hashimotofull完全一樣

總結ethash相比與bitcoin的挖礦演算法,增加了對記憶體使用的要求,要求礦工提供在挖礦過程中使用了大量記憶體的工作量證明,最終達到抵抗asic礦機的目的。

參考資料

1 ethash-design-rationale

2 what-actually-is-a-dag

3 why-dagger-hashimoto-for-ethereum

以太坊原始碼分析 Whisper

whisper具有以下基本特性和概念 通訊加密 每一條whisper訊息在網路上都是加密傳輸的,可以選擇非對稱加密 橢圓曲線 和對稱加密 aes gsm 兩種加密演算法之一。envelope 信封 envelope是網路中傳輸的whisper訊息的基本單位,它包含已加密的原始訊息以及訊息相關的控制資...

以太坊挖礦返回null原始碼分析

在以太坊版本1.7.3中,無論是dev環境或是公鏈環境在console中執行miner.start 始終返回null,而不是期待的true。這是為什麼呢?這篇文章就帶大家從原始碼中找找原因。在這個過程中我們會了解到更多底層的知識。首先看一下呼叫挖礦的程式,在console中我們執行的是 miner....

以太坊原始碼分析 交易的執行

以太坊是乙個執行智慧型合約的平台,被稱作可程式設計的區塊鏈,允許使用者將編寫的智慧型合約部署在區塊鏈上執行。而執行合約的主體便是以太坊虛擬機器 evm 區塊 交易 合約 區塊鏈由區塊 block 組成,而區塊中打包一定數量的交易 transaction 交易可能是乙個單純的轉賬操作,也可能是呼叫乙個...