1 eos 每500毫秒出乙個塊,每個生產節點連續出12個塊,然後切換到下一節點生產。
2 eos需要兩輪共識
新生產/接收的塊會放入記憶體塊分叉資料庫fork_db中,等待共識。
單節點不可逆塊:我們把完成第一輪共識的塊,叫做單節點不可逆塊。
全網不可逆塊: 完成第二輪共識的塊,叫全網不可逆塊。
完成兩輪共識的全網不可逆塊,才是我們常說的真正意義上的不可逆塊,會從fork_db中移出寫入block_log,實現落塊。
3 共識相關關鍵變數
下面是eos中定義的block_header_state資料結構,共識用到的大多數變數值都儲存在這裡:
struct block_header_state
//1 第一輪 ,水印值,記錄每個生產者生產的最後乙個塊的塊號。
std::map_producer_watermarks;
第一輪共識
1 計算節點1未確認塊數:目前鏈頭塊塊號6 - 節點水印值2(節點1生產的最後乙個塊)=4;
即生產7號塊時,前面有4個塊待節點1確認。
2 計算7號塊需要被幾個節點確認: 3(節點數)* 2/3 +1 = 3,將3放入confirm_count最後;
3 第一輪共識計算:實際就是對confirm_count陣列中儲存的待確認數進行減1計算。
塊待確認陣列confirm_count 在第一輪共識中的變動情況展示如下:
生產7塊前,裡面有4個待確認塊。
先將7塊的待確認數3插confirm_count的最後。
迴圈從confirm_count尾部對其中的值執行減1操作。當有confirm_count[i]==0成立,停止迴圈。i位置對應的塊號,即此次共識得到的單節點不可逆塊號,此時4號塊成為單節點不可逆塊,它之前的塊不用計算,都自動成為單節點不可逆塊。
移動confirm_count,清除4號塊之前所有塊。
第一輪共識完成,得到dpos_proposed_irreversible_blocknum=4。
第二輪共識
這裡主要用到producer_to_last_implied_irb,它是乙個map容器,裡面放的是生產節點的節點名及該節點對應的單點不可逆塊號,此處的單點不可逆塊號就是該節點在執行第一輪共識計算時得到的值。只有出塊節點的單節單節點不可逆值才會更新。
剛才生產7號塊時計算得到節點1的當前不可逆塊號是4,可推得此時節點3對應的值應該是2,節點2對應值0。當節點2生產第9個塊時,節點2第一輪共識得到的單節點不可逆塊號6, 其它節點不變,如下圖所示:
eos的第二輪共識演算法,會將producer_to_last_implied_irb中的塊號排序,從小到大取1/3位置的塊,成為最終不可逆塊。
下圖為根據eos塊生產流程畫出的塊共識流程,下面分別從生產節點作為生產者出塊和作為驗證節點收到兩種情況,結合**分別對兩輪共識流程展開進行分析。
3.1 出塊節點共識
3.1.1 第一輪共識
節點迴圈呼叫schedule_production_loop()函式進行生產迴圈,函式中會呼叫start_block()判斷是否該本節點出塊。
計算本塊需要確認的塊數:blocks_to_confirm = 鏈頭塊號 - 本節點水印值;
producer_plugin_impl::start_block_result producer_plugin_impl::start_block()
} ...
chain.start_block(block_time, blocks_to_confirm);
}
輪到本節點出塊,將出塊時間和blocks_to_confirm作為引數傳入controller_impl::start_block()函式,啟動出塊:
void start_block(block_timestamp_type when, uint16_t confirm_block_count,.. )
generate_next()中已將本次生產塊的待確認數加入了confirm_count中,下面開始第一輪共識計算:
void block_header_state::set_confirmed( uint16_t num_prev_blocks ) else
return;
}--i;
--blocks_to_confirm;}}
出塊時間到,節點會呼叫produce_block()函式進行一些收尾工作,比如計算默克爾根,塊簽名等,生產者水印值也是在這裡跟新的:
void producer_plugin_impl::produce_block()
3.1.2 第二輪共識
前面已經介紹了,在generate_next()中會呼叫calc_dpos_last_irreversible()函式進行第二輪共識計算,下面我來看一下具體的計算過程:
uint32_t block_header_state::calc_dpos_last_irreversible()const
if( blocknums.size() == 0 ) return 0;
std::sort( blocknums.begin(), blocknums.end() );
return blocknums[ (blocknums.size()-1) / 3 ];
}
* new_producer_to_last_implied_irb 是乙個map容器結構,裡面放的是《生產者,節點最後單節點不可逆號》 對,容器的到小等於active_schedule裡生產節點的數量。
* 構造了blocknums[]陣列,將new_producer_to_last_implied_irb中的單節點不可逆號複製到裡面,所以這裡blocknums的大小也等於實際生產節點的大小。
* 將blocknums按從小到大的順序排序,取其(blocknums.size()-1) / 3位置的塊號,成為全網不可逆塊號。
以21個生產節點為例,(blocknums.size()-1) / 3 =6,blocknums[6]位置的塊號,索引從0開始,即從塊號從大到小排第15個節點的塊號,由拜占庭共識演算法21×2/ 3+1=15,可以看出,此處計算雖然是取的1/ 3處的塊號,但它是逆序取的,所以第二輪共識實際也是一次拜占庭共識。
這裡還有乙個注意點,在進行生產節點切換有新節點加入時,producer_to_last_implied_irb中新加入節點的單節點不可逆塊號會使用當前鏈頭號進行初始化。
flat_mapnew_producer_to_last_implied_irb;
for( const auto& pro : active_schedule.producers ) else
3.2 驗證節點共識
這個start_block()和出塊時呼叫的start_block()是同一函式,所以前面進行的兩輪共識計算,這裡也會做一遍。只是這次做是為了和出塊節點保持狀態一直,做的是實際出塊者的共識過程,並不代表本節點共識了相應塊。更新的不可逆塊號也是實際出塊者的值。
eos中是21個節點出塊,每個節點連續出12個塊,切換下個生產者。每個塊需要:21*2/3 +1 =15個節點共識。
下圖為eos節點出塊序號表展示,節點1第一輪出1-12塊,接著節點2出11-24塊,圖中pirb為單節點不可逆塊號,irb為全網不可逆塊號。
星河公鏈
eos採用的共識機制是 EOS共識機制
eos在第一版 中使用的dpos共識機制,而在新一版的白書中,對共識機制進行了改進,使用bft dpos混合共識機制。使出塊速度從原來的3秒變為0.5秒,tps顯著提高,達到測試3590次 秒。eos第一版共識機制dpos eos現在系統執行的鏈用的共識機制是第一版 的,也就是純dpos共識機制。d...
EOS的共識機制 一
eos的共識機制由傳統的dpos 委託權益共識 公升級到bft dpos 拜占庭容錯 委託權益共識 eos 由21個節點 見證人,出塊者 參入。傳統 dpos 的特點 1 每3秒生產乙個區塊,每個出塊者生產乙個區塊。出塊順序是無序的。2 dpos的演算法中,每乙個區塊需要21個出塊者中的三分之二以上...
8 2 EOS區塊共識流程
eos共識分為兩個部分 prduce block 生產節點生產的區塊 confirm block 生產節點要確認的區塊 本地生產 接收到的塊 accept block 非生產節點接收到的區塊 plib 加入到備選的不可逆塊序號 lib 最終的不可逆區塊序號 下面的舉例不考慮網路延遲導致的漏塊情況 假...