1. 程式人生 > >eos原始碼賞析(十):EOS智慧合約入門之區塊上鍊

eos原始碼賞析(十):EOS智慧合約入門之區塊上鍊

或許我們還都記得美國隊長的勇敢、神武,為了捍衛自由和保衛人民而擁有的堅不可摧的盾牌,但我們還記得那個瘦弱到不堪一擊的史蒂夫.羅傑斯麼?血清的注射讓他變成了很多人心目中的英雄。那麼我們又可曾想過,美國隊長還會變成以前的那個因瘦弱的身軀而一直被人嘲笑的史蒂夫.羅傑斯麼,或許真的已經變不回去了,因為血清的注射是一個不可逆的過程,就如同eos中區塊產生、確認之後是一個不可逆的過程一樣。下面結合原始碼,承接上篇文章,出塊、廣播之後,對eos的上鍊過程進行一個簡單的分析。

 在前兩篇文章中分別介紹了eos系統中從出塊流程和訊號槽廣播機制的實現介紹了出塊之後區塊的資訊如何廣播的net_plugin的,具體廣播到net_plugin之後又做了什麼操作,我們在接下來的文章中會談到。區塊上鍊的主要流程包括以下幾個步驟:

  • 單節點區塊驗證(controller::sign_block)

  • 區塊確認(controller::commit_block)

  • 分叉資料庫儲存(fork_db::add)

  • 刪除老的區塊(fork_db::prune)

  • 觸發不可逆處理訊號(fork_db::signal irreversible)

  • 不可逆槽函式處理(controller::on_irreversible)

  • 入庫(db.commit)

在以前的文章中我們談到,區塊生產之後需要有個節點確認的過程,在單節點部署的情況下本節點產生區塊自然而然的本節點會直接確認掉,無需對其他節點的許可權進行校驗且不需要DPoS機制中超出2/3以上的節點對該區塊進行確認。此處,為了方便解釋,我們把區塊確認的程式碼拿出來,如圖1示,具體到sign這個函式,其內部分別呼叫了hash庫中的一些內容,最終將結果賦值給已生成區塊,其中進行了一系列hash轉換,較為繁瑣,感興趣的同學可以嘗試著去除錯一下。

圖1 單節點確認區塊

區塊確認被當前節點確認之後,會進入上鍊的流程。在controller.cpp的commit_block中,會將當前已生產且被當前節點確認的去add到fork_db中,如圖2中標註1所示:

圖2 區塊確認

 關於eos系統中的資料庫使用我們在接下來的文章中也會逐步的介紹,今天暫時先看下fork_db的功能及實現,圖3和圖4是對整個fork_db的概覽,通過其註釋內容我們可以看出fork_db其實並未將區塊存入持久化的資料庫,而是類似於一個臨時變數的儲存。簡單的將其註釋內容翻譯如下:

圖3 fork_db的結構

fork_database可以用來輕量管理所有潛在未確認的區塊的狀態資訊。當接收到一個新的區塊的時候,會被新增到fork_database中來。fork_database跟蹤了最長的鏈且記錄了最後一個不可逆區塊的編號。我們在上篇文章介紹emit訊號槽實現的時候提到了,區塊確認不可逆之後也會將區塊資訊廣播至net_plugin中去,當這個訊號量發出去之後,所有的在這個區塊之前的資訊就都被釋放掉了。

  基於此,我們可以簡單的認為區塊生成之後以一個臨時變數的形式儲存在fork_db中,等下一個區塊確認不可逆之後會將其從fork_db中抹去,並儲存至持久化的資料庫中去。上面我們一直提到不可逆訊號量的發射,可以看到在fork_db中定義了一個訊號量irreversible,如圖4中標註1所示:

圖4 訊號量irreversible

註釋中對其描述為,當確認一個區塊不可逆即刻將訊號廣播出去,一旦其不可逆,在其不為頭區塊的情況下,將會從fork_db中移除。那麼這個移除的過程是怎麼實現的呢,讓我們回到fork_db的add上來。

圖5 fork_database::add

  由於fork_database並非真實存在的資料庫,只是用來臨時的儲存一些資料,類似於我們將資料寫入到記憶體中去。在這裡,當區塊資訊add成功之後會獲取當前區塊的lib以及上一區塊的相關資訊,通過判斷,如果dpos不可逆區塊的lib大於在此之前區塊資訊的lib,則將老的區塊資訊清除。

  在這裡我們舉個簡單的例子,區塊編號為10的區塊資訊add到fork_db中來,也就是在此之前dpos_irreversible_blocknum為9,而獲取到的oldest區塊編號為8,此時就會呼叫prune將編號為8之前的區塊資訊從fork_db中移除出去。下面讓我們來看看prune具體做了什麼操作,如圖6所示:

圖6 fork_db::prune

         prune會根據block_state的id從fork_db遍歷所有已存在的資料(index中)去查詢是否存在該區塊資訊,如果存在則將其以irreversible訊號的形式連線到槽函式on_irreversible中去,之後將其從index中移除,這是個非同步的過程。現在我們可以看到,基本上已經實現了這個不可逆的過程,但還有一個關鍵步驟,也就是這些區塊資訊的資料儲存我們還沒有做。我們來繼續on_irreversible,如圖7所示:

圖7 controller::on_irreversible

       到了這裡,我們看到首先將區塊資訊存到資料庫中,此處的db.commit是和fork_db不同的,我們可以看到關於db的宣告,是chainbase::database的一種。關於eos中所使用的資料庫相關操作,內容也較多。我們本篇主要是承接前幾篇文章中區塊生成、區塊廣播、區塊上鍊,到這裡區塊真正的入庫了,也算完成了整個區塊生產的過程。最後依然是使用emit的方式,將不可逆的區塊資訊廣播至net_plugin中去。

       通過這三篇文章我們對原始碼中區塊的產生應該有了一定的瞭解,這三篇也可以看做一個簡短的系列,其實我們在eos系統中每一次有意義的操作如我們經常做的交易,都可以看成一個區塊生成的過程。接下來的原始碼閱讀方向暫未確定,也可根據讀者需求去做轉換,另外本公眾號前三篇文已不再適配當前程式碼,可適當忽略。

      我們通篇在提不可逆,不可逆正是區塊鏈技術的一大特徵,區塊鏈同時還具有可追溯性這個特徵,想到當下那些惡貫滿盈的假疫苗生產者、銷售者,區塊鏈技術應用於這些行業或許會讓這些人顫抖,顫抖到他們不敢再開出惡之花。

  如果你覺得我的文章對你有一定的幫助,請點選文章末尾的喜歡該作者。

      如果你對eos開發感興趣,歡迎關注本公眾號,一起學習eos開發。 

微信公眾號

         有任何疑問或者指教請新增本人個人微信,當然有對eos開發感興趣或者金庸粉的也可以新增一起交流,備註eos開發或金庸。

個人微訊號