以太坊挖礦原理

以太坊的共識機制是 PoW(Proof of Work 工做量證實機制),使用的算法是Ethash,這種算法是對 Dagger-Hashimoto算法的改良版本,流程大概以下算法

1.對於每個塊,首先計算一個種子(seed),該種子只和當前塊的信息有關;而後根據種子生成一個32M的隨機數據集(cache)微信

2. 根據Cache生成一個1GB大小的數據集合DAG(有向非循環圖),它是一個完整的搜索空間,挖礦的過程就是從DAG中隨機選擇元素(相似於比特幣挖礦中查找合適Nonce)再進行哈希運算,能夠從Cache快速計算DAG指定位置的元素,進而哈希驗證區塊鏈


要求對Cache和DAG進行週期性更新,每1000個塊更新一次,而且規定DAG的大小隨着時間推移線性增加,從1G開始,每一年大約增加7G左右。atom

爲了更好的瞭解這部分。咱們能夠簡單的看下 go-ethereum 的代碼spa

1. 在 miner.go裏調用 New方法生成一個礦工。blog

 

/**
   利用區塊鏈建立時候的一些配置,以及共識引擎consensus.Engine等參數先是生成一個礦工,而後
   讓礦工註冊一個cpu運算引擎,同時經過 update 來監聽同步狀態並更新挖礦狀態
**/
func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine) *Miner {
	miner := &Miner{
		eth:      eth,
		mux:      mux,
		engine:   engine,
		worker:   newWorker(config, engine, common.Address{}, eth, mux),
		canStart: 1,
	}
	miner.Register(NewCpuAgent(eth.BlockChain(), engine))
	go miner.update()

	return miner
}

 

在update方法裏有一個須要注意:索引

case downloader.StartEvent:
			atomic.StoreInt32(&self.canStart, 0)
			if self.Mining() {
				self.Stop()
				atomic.StoreInt32(&self.shouldStart, 1)
				log.Info("Mining aborted due to sync")
			}

 能夠看到若是當前處於 區塊的同步中,則挖礦的操做須要中止,直到同步操做結束(同步成功或是失敗),若是原來已經執行了挖礦操做的,則繼續開啓挖礦操做。接口

2.在 Register方法中調用worker的Agent接口裏的Start方法,該方法在agent.go裏實現。在agent.go裏調用 mine進行挖礦操做。內存

func (self *CpuAgent) mine(work *Work, stop <-chan struct{}) {
       //調用Seal接口,在sealer.go裏實現,進行Ethash算法的實現
	if result, err := self.engine.Seal(self.chain, work.Block, stop); result != nil {
		log.Info("Successfully sealed new block", "number", result.Number(), "hash", result.Hash())
		self.returnCh <- &Result{work, result}
	} else {
		if err != nil {
			log.Warn("Block sealing failed", "err", err)
		}
		self.returnCh <- nil
	}
}

3. 在sealer.go的miner進行挖礦和結果比對,查找是否挖礦成功。get

   經過256/difficulty 生成一個target值,該值用於後面和計算出來的隨機數比較,若是計算出來的隨機數比target更小,則挖礦成功。同時經過當前所在的區塊號,生成一個完整的dataset。

      var (
               
	        //target的計算方法是 256/difficulty 的一個int值
		target = new(big.Int).Div(maxUint256, header.Difficulty)

                //當前是第幾塊
		number  = header.Number.Uint64()
                //生成一個dataset,也就是咱們說的搜索或是匹配空間
		dataset = ethash.dataset(number)
	)

 具體過程以下:

  1)經過number號獲得當前塊處於第幾個epoch.(每30000個區塊爲一個epoch,時間窗口爲125小時,大約5.2天),經過所在的epoch爲索引獲取當前內存中是否有dataset

  2)若是沒有,先會看內存裏的總dataset是否大於 dagsinmemory(默認爲1),若是大於,則須要把最先的一個dataset刪除

  3)同時查看是否有pre-generated dataset cache,該數據存在與磁盤空間中。若是有這個數據,而且和當前區塊在同一個 epoch. 就用這個pre-generated dataset做爲當前dataset.

  4)若是上述不符合,則從新生成一個dataset. 若是在這個過程當中,發現原來pre-generated dataset爲空,或是它的epoch和當前所在區塊的epoch不一致,則須要用新生成的dataset做爲pre-generated dataset,賦值給它

   5) 生成dataset後,經過dataset,利用keccak512算法,生成一個1GB大小的數據集合DAG

   6) 接下來就是不停循環的利用hashimoto算法(基於Keccak256算法)計算出一個結果值,而後和target進行比較。若是比target小則成功,不然就繼續

 

 

 

 


 歡迎你們關注微信號:蝸牛講技術。掃下面的二維碼

相關文章
相關標籤/搜索